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