nm-setting-bond.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
  2. /*
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public
  5. * License as published by the Free Software Foundation; either
  6. * version 2 of the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the
  15. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301 USA.
  17. *
  18. * Copyright 2011 - 2013 Red Hat, Inc.
  19. */
  20. #include "nm-default.h"
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #include <netinet/in.h>
  25. #include <arpa/inet.h>
  26. #include <dbus/dbus-glib.h>
  27. #include "nm-setting-bond.h"
  28. #include "nm-param-spec-specialized.h"
  29. #include "nm-utils.h"
  30. #include "nm-utils-private.h"
  31. #include "nm-dbus-glib-types.h"
  32. #include "nm-setting-private.h"
  33. /**
  34. * SECTION:nm-setting-bond
  35. * @short_description: Describes connection properties for bonds
  36. * @include: nm-setting-bond.h
  37. *
  38. * The #NMSettingBond object is a #NMSetting subclass that describes properties
  39. * necessary for bond connections.
  40. **/
  41. /**
  42. * nm_setting_bond_error_quark:
  43. *
  44. * Registers an error quark for #NMSettingBond if necessary.
  45. *
  46. * Returns: the error quark used for #NMSettingBond errors.
  47. **/
  48. GQuark
  49. nm_setting_bond_error_quark (void)
  50. {
  51. static GQuark quark;
  52. if (G_UNLIKELY (!quark))
  53. quark = g_quark_from_static_string ("nm-setting-bond-error-quark");
  54. return quark;
  55. }
  56. G_DEFINE_TYPE_WITH_CODE (NMSettingBond, nm_setting_bond, NM_TYPE_SETTING,
  57. _nm_register_setting (NM_SETTING_BOND_SETTING_NAME,
  58. g_define_type_id,
  59. 1,
  60. NM_SETTING_BOND_ERROR))
  61. NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_BOND)
  62. #define NM_SETTING_BOND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BOND, NMSettingBondPrivate))
  63. typedef struct {
  64. char *interface_name;
  65. GHashTable *options;
  66. } NMSettingBondPrivate;
  67. enum {
  68. PROP_0,
  69. PROP_INTERFACE_NAME,
  70. PROP_OPTIONS,
  71. LAST_PROP
  72. };
  73. enum {
  74. TYPE_INT,
  75. TYPE_STR,
  76. TYPE_BOTH,
  77. TYPE_IP,
  78. TYPE_IFNAME,
  79. };
  80. typedef struct {
  81. const char *opt;
  82. const char *val;
  83. guint opt_type;
  84. guint min;
  85. guint max;
  86. char *list[10];
  87. } BondDefault;
  88. static const BondDefault defaults[] = {
  89. { NM_SETTING_BOND_OPTION_MODE, "balance-rr", TYPE_BOTH, 0, 6,
  90. { "balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb", NULL } },
  91. { NM_SETTING_BOND_OPTION_MIIMON, "100", TYPE_INT, 0, G_MAXINT },
  92. { NM_SETTING_BOND_OPTION_DOWNDELAY, "0", TYPE_INT, 0, G_MAXINT },
  93. { NM_SETTING_BOND_OPTION_UPDELAY, "0", TYPE_INT, 0, G_MAXINT },
  94. { NM_SETTING_BOND_OPTION_ARP_INTERVAL, "0", TYPE_INT, 0, G_MAXINT },
  95. { NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "", TYPE_IP },
  96. { NM_SETTING_BOND_OPTION_ARP_VALIDATE, "0", TYPE_BOTH, 0, 3,
  97. { "none", "active", "backup", "all", NULL } },
  98. { NM_SETTING_BOND_OPTION_PRIMARY, "", TYPE_IFNAME },
  99. { NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, "0", TYPE_BOTH, 0, 2,
  100. { "always", "better", "failure", NULL } },
  101. { NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, "0", TYPE_BOTH, 0, 2,
  102. { "none", "active", "follow", NULL } },
  103. { NM_SETTING_BOND_OPTION_USE_CARRIER, "1", TYPE_INT, 0, 1 },
  104. { NM_SETTING_BOND_OPTION_AD_SELECT, "0", TYPE_BOTH, 0, 2,
  105. { "stable", "bandwidth", "count", NULL } },
  106. { NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, "0", TYPE_BOTH, 0, 2,
  107. { "layer2", "layer3+4", "layer2+3", NULL } },
  108. { NM_SETTING_BOND_OPTION_RESEND_IGMP, "1", TYPE_INT, 0, 255 },
  109. { NM_SETTING_BOND_OPTION_LACP_RATE, "0", TYPE_BOTH, 0, 1,
  110. { "slow", "fast", NULL } },
  111. };
  112. /**
  113. * nm_setting_bond_new:
  114. *
  115. * Creates a new #NMSettingBond object with default values.
  116. *
  117. * Returns: (transfer full): the new empty #NMSettingBond object
  118. **/
  119. NMSetting *
  120. nm_setting_bond_new (void)
  121. {
  122. return (NMSetting *) g_object_new (NM_TYPE_SETTING_BOND, NULL);
  123. }
  124. /**
  125. * nm_setting_bond_get_interface_name:
  126. * @setting: the #NMSettingBond
  127. *
  128. * Returns: the #NMSettingBond:interface-name property of the setting
  129. **/
  130. const char *
  131. nm_setting_bond_get_interface_name (NMSettingBond *setting)
  132. {
  133. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL);
  134. return NM_SETTING_BOND_GET_PRIVATE (setting)->interface_name;
  135. }
  136. /**
  137. * nm_setting_bond_get_num_options:
  138. * @setting: the #NMSettingBond
  139. *
  140. * Returns the number of options that should be set for this bond when it
  141. * is activated. This can be used to retrieve each option individually
  142. * using nm_setting_bond_get_option().
  143. *
  144. * Returns: the number of bonding options
  145. **/
  146. guint32
  147. nm_setting_bond_get_num_options (NMSettingBond *setting)
  148. {
  149. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), 0);
  150. return g_hash_table_size (NM_SETTING_BOND_GET_PRIVATE (setting)->options);
  151. }
  152. /**
  153. * nm_setting_bond_get_option:
  154. * @setting: the #NMSettingBond
  155. * @idx: index of the desired option, from 0 to
  156. * nm_setting_bond_get_num_options() - 1
  157. * @out_name: (out): on return, the name of the bonding option; this
  158. * value is owned by the setting and should not be modified
  159. * @out_value: (out): on return, the value of the name of the bonding
  160. * option; this value is owned by the setting and should not be modified
  161. *
  162. * Given an index, return the value of the bonding option at that index. Indexes
  163. * are *not* guaranteed to be static across modifications to options done by
  164. * nm_setting_bond_add_option() and nm_setting_bond_remove_option(),
  165. * and should not be used to refer to options except for short periods of time
  166. * such as during option iteration.
  167. *
  168. * Returns: %TRUE on success if the index was valid and an option was found,
  169. * %FALSE if the index was invalid (ie, greater than the number of options
  170. * currently held by the setting)
  171. **/
  172. gboolean
  173. nm_setting_bond_get_option (NMSettingBond *setting,
  174. guint32 idx,
  175. const char **out_name,
  176. const char **out_value)
  177. {
  178. NMSettingBondPrivate *priv;
  179. GList *keys;
  180. const char *_key = NULL, *_value = NULL;
  181. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE);
  182. priv = NM_SETTING_BOND_GET_PRIVATE (setting);
  183. if (idx >= nm_setting_bond_get_num_options (setting))
  184. return FALSE;
  185. keys = g_hash_table_get_keys (priv->options);
  186. _key = g_list_nth_data (keys, idx);
  187. _value = g_hash_table_lookup (priv->options, _key);
  188. if (out_name)
  189. *out_name = _key;
  190. if (out_value)
  191. *out_value = _value;
  192. g_list_free (keys);
  193. return TRUE;
  194. }
  195. static gboolean
  196. validate_int (const char *name, const char *value, const BondDefault *def)
  197. {
  198. long num;
  199. guint i;
  200. for (i = 0; i < strlen (value); i++) {
  201. if (!g_ascii_isdigit (value[i]) && value[i] != '-')
  202. return FALSE;
  203. }
  204. errno = 0;
  205. num = strtol (value, NULL, 10);
  206. if (errno)
  207. return FALSE;
  208. if (num < def->min || num > def->max)
  209. return FALSE;
  210. return TRUE;
  211. }
  212. static gboolean
  213. validate_list (const char *name, const char *value, const BondDefault *def)
  214. {
  215. guint i;
  216. for (i = 0; i < G_N_ELEMENTS (def->list) && def->list[i]; i++) {
  217. if (g_strcmp0 (def->list[i], value) == 0)
  218. return TRUE;
  219. }
  220. /* empty validation list means all values pass */
  221. return def->list[0] == NULL ? TRUE : FALSE;
  222. }
  223. static gboolean
  224. validate_ip (const char *name, const char *value)
  225. {
  226. gs_free char *value_clone = NULL;
  227. struct in_addr addr;
  228. if (!value || !value[0])
  229. return FALSE;
  230. value_clone = g_strdup (value);
  231. value = value_clone;
  232. for (;;) {
  233. char *eow;
  234. /* we do not skip over empty words. E.g
  235. * "192.168.1.1," is an error.
  236. *
  237. * ... for no particular reason. */
  238. eow = strchr (value, ',');
  239. if (eow)
  240. *eow = '\0';
  241. if (inet_pton (AF_INET, value, &addr) != 1)
  242. return FALSE;
  243. if (!eow)
  244. break;
  245. value = eow + 1;
  246. }
  247. return TRUE;
  248. }
  249. static gboolean
  250. validate_ifname (const char *name, const char *value)
  251. {
  252. if (!value || !value[0])
  253. return FALSE;
  254. return nm_utils_iface_valid_name (value);
  255. }
  256. /**
  257. * nm_setting_bond_validate_option:
  258. * @name: the name of the option to validate
  259. * @value: the value of the option to validate
  260. *
  261. * Checks whether @name is a valid bond option and @value is a valid value for
  262. * the @name. If @value is %NULL, the function only validates the option name.
  263. *
  264. * Returns: %TRUE, if the @value is valid for the given name.
  265. * If the @name is not a valid option, %FALSE will be returned.
  266. *
  267. * Since: 0.9.10
  268. **/
  269. gboolean
  270. nm_setting_bond_validate_option (const char *name,
  271. const char *value)
  272. {
  273. guint i;
  274. if (!name || !name[0])
  275. return FALSE;
  276. for (i = 0; i < G_N_ELEMENTS (defaults); i++) {
  277. if (g_strcmp0 (defaults[i].opt, name) == 0) {
  278. if (value == NULL)
  279. return TRUE;
  280. switch (defaults[i].opt_type) {
  281. case TYPE_INT:
  282. return validate_int (name, value, &defaults[i]);
  283. case TYPE_STR:
  284. return validate_list (name, value, &defaults[i]);
  285. case TYPE_BOTH:
  286. return ( validate_int (name, value, &defaults[i])
  287. || validate_list (name, value, &defaults[i]));
  288. case TYPE_IP:
  289. return validate_ip (name, value);
  290. case TYPE_IFNAME:
  291. return validate_ifname (name, value);
  292. }
  293. return FALSE;
  294. }
  295. }
  296. return FALSE;
  297. }
  298. /**
  299. * nm_setting_bond_get_option_by_name:
  300. * @setting: the #NMSettingBond
  301. * @name: the option name for which to retrieve the value
  302. *
  303. * Returns the value associated with the bonding option specified by
  304. * @name, if it exists.
  305. *
  306. * Returns: the value, or %NULL if the key/value pair was never added to the
  307. * setting; the value is owned by the setting and must not be modified
  308. **/
  309. const char *
  310. nm_setting_bond_get_option_by_name (NMSettingBond *setting,
  311. const char *name)
  312. {
  313. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL);
  314. if (!nm_setting_bond_validate_option (name, NULL))
  315. return NULL;
  316. return g_hash_table_lookup (NM_SETTING_BOND_GET_PRIVATE (setting)->options, name);
  317. }
  318. /**
  319. * nm_setting_bond_add_option:
  320. * @setting: the #NMSettingBond
  321. * @name: name for the option
  322. * @value: value for the option
  323. *
  324. * Add an option to the table. The option is compared to an internal list
  325. * of allowed options. Option names may contain only alphanumeric characters
  326. * (ie [a-zA-Z0-9]). Adding a new name replaces any existing name/value pair
  327. * that may already exist.
  328. *
  329. * The order of how to set several options is relevant because there are options
  330. * that conflict with each other.
  331. *
  332. * Returns: %TRUE if the option was valid and was added to the internal option
  333. * list, %FALSE if it was not.
  334. **/
  335. gboolean
  336. nm_setting_bond_add_option (NMSettingBond *setting,
  337. const char *name,
  338. const char *value)
  339. {
  340. NMSettingBondPrivate *priv;
  341. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE);
  342. if (!value || !nm_setting_bond_validate_option (name, value))
  343. return FALSE;
  344. priv = NM_SETTING_BOND_GET_PRIVATE (setting);
  345. g_hash_table_insert (priv->options, g_strdup (name), g_strdup (value));
  346. if ( !strcmp (name, NM_SETTING_BOND_OPTION_MIIMON)
  347. && strcmp (value, "0") != 0) {
  348. g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
  349. g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
  350. } else if ( !strcmp (name, NM_SETTING_BOND_OPTION_ARP_INTERVAL)
  351. && strcmp (value, "0") != 0) {
  352. g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_MIIMON);
  353. g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY);
  354. g_hash_table_remove (priv->options, NM_SETTING_BOND_OPTION_UPDELAY);
  355. }
  356. g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS);
  357. return TRUE;
  358. }
  359. /**
  360. * nm_setting_bond_remove_option:
  361. * @setting: the #NMSettingBond
  362. * @name: name of the option to remove
  363. *
  364. * Remove the bonding option referenced by @name from the internal option
  365. * list.
  366. *
  367. * Returns: %TRUE if the option was found and removed from the internal option
  368. * list, %FALSE if it was not.
  369. **/
  370. gboolean
  371. nm_setting_bond_remove_option (NMSettingBond *setting,
  372. const char *name)
  373. {
  374. gboolean found;
  375. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), FALSE);
  376. if (!nm_setting_bond_validate_option (name, NULL))
  377. return FALSE;
  378. found = g_hash_table_remove (NM_SETTING_BOND_GET_PRIVATE (setting)->options, name);
  379. if (found)
  380. g_object_notify (G_OBJECT (setting), NM_SETTING_BOND_OPTIONS);
  381. return found;
  382. }
  383. /**
  384. * nm_setting_bond_get_valid_options:
  385. * @setting: the #NMSettingBond
  386. *
  387. * Returns a list of valid bond options.
  388. *
  389. * Returns: (transfer none): a %NULL-terminated array of strings of valid bond options.
  390. **/
  391. const char **
  392. nm_setting_bond_get_valid_options (NMSettingBond *setting)
  393. {
  394. static const char *array[G_N_ELEMENTS (defaults) + 1] = { NULL };
  395. int i;
  396. /* initialize the array once */
  397. if (G_UNLIKELY (array[0] == NULL)) {
  398. for (i = 0; i < G_N_ELEMENTS (defaults); i++)
  399. array[i] = defaults[i].opt;
  400. array[i] = NULL;
  401. }
  402. return array;
  403. }
  404. /**
  405. * nm_setting_bond_get_option_default:
  406. * @setting: the #NMSettingBond
  407. * @name: the name of the option
  408. *
  409. * Returns: the value of the bond option if not overridden by an entry in
  410. * the #NMSettingBond:options property.
  411. **/
  412. const char *
  413. nm_setting_bond_get_option_default (NMSettingBond *setting, const char *name)
  414. {
  415. guint i;
  416. g_return_val_if_fail (NM_IS_SETTING_BOND (setting), NULL);
  417. g_return_val_if_fail (nm_setting_bond_validate_option (name, NULL), NULL);
  418. for (i = 0; i < G_N_ELEMENTS (defaults); i++) {
  419. if (g_strcmp0 (defaults[i].opt, name) == 0)
  420. return defaults[i].val;
  421. }
  422. /* Any option that passes nm_setting_bond_validate_option() should also be found in defaults */
  423. g_assert_not_reached ();
  424. }
  425. static gboolean
  426. verify (NMSetting *setting, GSList *all_settings, GError **error)
  427. {
  428. NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting);
  429. GHashTableIter iter;
  430. const char *key, *value;
  431. const char *valid_modes[] = { "balance-rr",
  432. "active-backup",
  433. "balance-xor",
  434. "broadcast",
  435. "802.3ad",
  436. "balance-tlb",
  437. "balance-alb",
  438. NULL };
  439. int miimon = 0, arp_interval = 0;
  440. const char *arp_ip_target = NULL;
  441. const char *lacp_rate;
  442. const char *primary;
  443. g_hash_table_iter_init (&iter, priv->options);
  444. while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) {
  445. if (!value[0] || !nm_setting_bond_validate_option (key, value)) {
  446. g_set_error (error,
  447. NM_SETTING_BOND_ERROR,
  448. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  449. _("invalid option '%s' or its value '%s'"),
  450. key, value);
  451. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  452. return FALSE;
  453. }
  454. }
  455. value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MIIMON);
  456. if (value)
  457. miimon = atoi (value);
  458. value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
  459. if (value)
  460. arp_interval = atoi (value);
  461. /* Can only set one of miimon and arp_interval */
  462. if (miimon > 0 && arp_interval > 0) {
  463. g_set_error (error,
  464. NM_SETTING_BOND_ERROR,
  465. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  466. _("only one of '%s' and '%s' can be set"),
  467. NM_SETTING_BOND_OPTION_MIIMON,
  468. NM_SETTING_BOND_OPTION_ARP_INTERVAL);
  469. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  470. }
  471. value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MODE);
  472. if (!value) {
  473. g_set_error (error,
  474. NM_SETTING_BOND_ERROR,
  475. NM_SETTING_BOND_ERROR_MISSING_OPTION,
  476. _("mandatory option '%s' is missing"),
  477. NM_SETTING_BOND_OPTION_MODE);
  478. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  479. return FALSE;
  480. }
  481. if (!g_strv_contains (valid_modes, value)) {
  482. g_set_error (error,
  483. NM_SETTING_BOND_ERROR,
  484. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  485. _("'%s' is not a valid value for '%s'"),
  486. value, NM_SETTING_BOND_OPTION_MODE);
  487. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  488. return FALSE;
  489. }
  490. /* Make sure mode is compatible with other settings */
  491. if ( strcmp (value, "balance-alb") == 0
  492. || strcmp (value, "balance-tlb") == 0) {
  493. if (arp_interval > 0) {
  494. g_set_error (error,
  495. NM_SETTING_BOND_ERROR,
  496. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  497. _("'%s=%s' is incompatible with '%s > 0'"),
  498. NM_SETTING_BOND_OPTION_MODE, value, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
  499. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  500. return FALSE;
  501. }
  502. }
  503. primary = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_PRIMARY);
  504. if (strcmp (value, "active-backup") == 0) {
  505. if (primary && !nm_utils_iface_valid_name (primary)) {
  506. g_set_error (error,
  507. NM_SETTING_BOND_ERROR,
  508. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  509. _("'%s' is not a valid interface name for '%s' option"),
  510. primary, NM_SETTING_BOND_OPTION_PRIMARY);
  511. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  512. return FALSE;
  513. }
  514. } else {
  515. if (primary) {
  516. g_set_error (error,
  517. NM_SETTING_BOND_ERROR,
  518. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  519. _("'%s' option is only valid for '%s=%s'"),
  520. NM_SETTING_BOND_OPTION_PRIMARY,
  521. NM_SETTING_BOND_OPTION_MODE, "active-backup");
  522. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  523. return FALSE;
  524. }
  525. }
  526. if (nm_setting_find_in_list (all_settings, NM_SETTING_INFINIBAND_SETTING_NAME)) {
  527. if (strcmp (value, "active-backup") != 0) {
  528. g_set_error (error,
  529. NM_SETTING_BOND_ERROR,
  530. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  531. _("'%s=%s' is not a valid configuration for '%s'"),
  532. NM_SETTING_BOND_OPTION_MODE, value, NM_SETTING_INFINIBAND_SETTING_NAME);
  533. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  534. return FALSE;
  535. }
  536. }
  537. if (miimon == 0) {
  538. /* updelay and downdelay can only be used with miimon */
  539. if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_UPDELAY)) {
  540. g_set_error (error,
  541. NM_SETTING_BOND_ERROR,
  542. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  543. _("'%s' option requires '%s' option to be set"),
  544. NM_SETTING_BOND_OPTION_UPDELAY, NM_SETTING_BOND_OPTION_MIIMON);
  545. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  546. return FALSE;
  547. }
  548. if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY)) {
  549. g_set_error (error,
  550. NM_SETTING_BOND_ERROR,
  551. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  552. _("'%s' option requires '%s' option to be set"),
  553. NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_MIIMON);
  554. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  555. return FALSE;
  556. }
  557. }
  558. /* arp_ip_target can only be used with arp_interval, and must
  559. * contain a comma-separated list of IPv4 addresses.
  560. */
  561. arp_ip_target = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
  562. if (arp_interval > 0) {
  563. char **addrs;
  564. guint32 addr;
  565. int i;
  566. if (!arp_ip_target) {
  567. g_set_error (error,
  568. NM_SETTING_BOND_ERROR,
  569. NM_SETTING_BOND_ERROR_MISSING_OPTION,
  570. _("'%s' option requires '%s' option to be set"),
  571. NM_SETTING_BOND_OPTION_ARP_INTERVAL, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
  572. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  573. return FALSE;
  574. }
  575. addrs = g_strsplit (arp_ip_target, ",", -1);
  576. if (!addrs[0]) {
  577. g_set_error (error,
  578. NM_SETTING_BOND_ERROR,
  579. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  580. _("'%s' option is empty"),
  581. NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
  582. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  583. g_strfreev (addrs);
  584. return FALSE;
  585. }
  586. for (i = 0; addrs[i]; i++) {
  587. if (!inet_pton (AF_INET, addrs[i], &addr)) {
  588. g_set_error (error,
  589. NM_SETTING_BOND_ERROR,
  590. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  591. _("'%s' is not a valid IPv4 address for '%s' option"),
  592. NM_SETTING_BOND_OPTION_ARP_IP_TARGET, addrs[i]);
  593. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  594. g_strfreev (addrs);
  595. return FALSE;
  596. }
  597. }
  598. g_strfreev (addrs);
  599. } else {
  600. if (arp_ip_target) {
  601. g_set_error (error,
  602. NM_SETTING_BOND_ERROR,
  603. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  604. _("'%s' option requires '%s' option to be set"),
  605. NM_SETTING_BOND_OPTION_ARP_IP_TARGET, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
  606. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  607. return FALSE;
  608. }
  609. }
  610. lacp_rate = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_LACP_RATE);
  611. if ( lacp_rate
  612. && (g_strcmp0 (value, "802.3ad") != 0 && g_strcmp0 (value, "4") != 0)
  613. && (strcmp (lacp_rate, "slow") != 0 && strcmp (lacp_rate, "0") != 0)) {
  614. g_set_error (error,
  615. NM_SETTING_BOND_ERROR,
  616. NM_SETTING_BOND_ERROR_INVALID_OPTION,
  617. _("'%s' option is only valid with mode '%s'"),
  618. NM_SETTING_BOND_OPTION_LACP_RATE, "802.3ad");
  619. g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
  620. return FALSE;
  621. }
  622. return _nm_setting_verify_deprecated_virtual_iface_name (
  623. priv->interface_name, FALSE,
  624. NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_INTERFACE_NAME,
  625. NM_SETTING_BOND_ERROR,
  626. NM_SETTING_BOND_ERROR_INVALID_PROPERTY,
  627. NM_SETTING_BOND_ERROR_MISSING_PROPERTY,
  628. all_settings, error);
  629. }
  630. static const char *
  631. get_virtual_iface_name (NMSetting *setting)
  632. {
  633. NMSettingBond *self = NM_SETTING_BOND (setting);
  634. return nm_setting_bond_get_interface_name (self);
  635. }
  636. static void
  637. nm_setting_bond_init (NMSettingBond *setting)
  638. {
  639. NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting);
  640. priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
  641. /* Default values: */
  642. nm_setting_bond_add_option (setting, NM_SETTING_BOND_OPTION_MODE, "balance-rr");
  643. }
  644. static void
  645. finalize (GObject *object)
  646. {
  647. NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object);
  648. g_free (priv->interface_name);
  649. g_hash_table_destroy (priv->options);
  650. G_OBJECT_CLASS (nm_setting_bond_parent_class)->finalize (object);
  651. }
  652. static void
  653. copy_hash (gpointer key, gpointer value, gpointer user_data)
  654. {
  655. g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), g_strdup (value));
  656. }
  657. static void
  658. set_property (GObject *object, guint prop_id,
  659. const GValue *value, GParamSpec *pspec)
  660. {
  661. NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object);
  662. GHashTable *new_hash;
  663. switch (prop_id) {
  664. case PROP_INTERFACE_NAME:
  665. g_free (priv->interface_name);
  666. priv->interface_name = g_value_dup_string (value);
  667. break;
  668. case PROP_OPTIONS:
  669. /* Must make a deep copy of the hash table here... */
  670. g_hash_table_remove_all (priv->options);
  671. new_hash = g_value_get_boxed (value);
  672. if (new_hash)
  673. g_hash_table_foreach (new_hash, copy_hash, priv->options);
  674. break;
  675. default:
  676. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  677. break;
  678. }
  679. }
  680. static void
  681. get_property (GObject *object, guint prop_id,
  682. GValue *value, GParamSpec *pspec)
  683. {
  684. NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (object);
  685. NMSettingBond *setting = NM_SETTING_BOND (object);
  686. switch (prop_id) {
  687. case PROP_INTERFACE_NAME:
  688. g_value_set_string (value, nm_setting_bond_get_interface_name (setting));
  689. break;
  690. case PROP_OPTIONS:
  691. g_value_set_boxed (value, priv->options);
  692. break;
  693. default:
  694. G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  695. break;
  696. }
  697. }
  698. static void
  699. nm_setting_bond_class_init (NMSettingBondClass *setting_class)
  700. {
  701. GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
  702. NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
  703. g_type_class_add_private (setting_class, sizeof (NMSettingBondPrivate));
  704. /* virtual methods */
  705. object_class->set_property = set_property;
  706. object_class->get_property = get_property;
  707. object_class->finalize = finalize;
  708. parent_class->verify = verify;
  709. parent_class->get_virtual_iface_name = get_virtual_iface_name;
  710. /* Properties */
  711. /**
  712. * NMSettingBond:interface-name:
  713. *
  714. * The name of the virtual in-kernel bonding network interface
  715. **/
  716. g_object_class_install_property
  717. (object_class, PROP_INTERFACE_NAME,
  718. g_param_spec_string (NM_SETTING_BOND_INTERFACE_NAME, "", "",
  719. NULL,
  720. G_PARAM_READWRITE |
  721. NM_SETTING_PARAM_INFERRABLE |
  722. G_PARAM_STATIC_STRINGS));
  723. /**
  724. * NMSettingBond:options:
  725. *
  726. * Dictionary of key/value pairs of bonding options. Both keys and values
  727. * must be strings. Option names must contain only alphanumeric characters
  728. * (ie, [a-zA-Z0-9]).
  729. **/
  730. g_object_class_install_property
  731. (object_class, PROP_OPTIONS,
  732. _nm_param_spec_specialized (NM_SETTING_BOND_OPTIONS, "", "",
  733. DBUS_TYPE_G_MAP_OF_STRING,
  734. G_PARAM_READWRITE |
  735. NM_SETTING_PARAM_INFERRABLE |
  736. G_PARAM_STATIC_STRINGS));
  737. }