Merge branch 'th/bgo729844_set_bridge_mac_address'

https://bugzilla.gnome.org/show_bug.cgi?id=729844

Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller 2014-05-30 17:03:20 +02:00
commit fad5472b34
20 changed files with 217 additions and 41 deletions

View file

@ -947,7 +947,7 @@ _nmcli()
OPTIONS_IP=()
;;
bridge)
OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time)
OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time mac)
;;
bridge-|bridge-s|bridge-sl|bridge-sla|bridge-slav|bridge-slave)
OPTIONS_TYPED=(master priority path-cost hairpin)

View file

@ -395,7 +395,8 @@ usage_connection_add (void)
" [forward-delay <2-30>]\n"
" [hello-time <1-10>]\n"
" [max-age <6-40>]\n"
" [ageing-time <0-1000000>]\n\n"
" [ageing-time <0-1000000>]\n"
" [mac <MAC address>]\n\n"
" bridge-slave: master <master (ifname, or connection UUID or name)>\n"
" [priority <0-63>]\n"
" [path-cost <1-65535>]\n"
@ -3320,8 +3321,8 @@ do_questionnaire_team_slave (char **config)
}
static void
do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay,
char **hello_time, char **max_age, char **ageing_time)
do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay, char **hello_time,
char **max_age, char **ageing_time, char **mac)
{
char *answer;
gboolean answer_bool;
@ -3330,7 +3331,7 @@ do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay,
GError *error = NULL;
/* Ask for optional 'bridge' arguments. */
printf (_("There are 6 optional arguments for 'bridge' connection type.\n"));
printf (_("There are 7 optional arguments for 'bridge' connection type.\n"));
answer = nmc_get_user_input (_("Do you want to provide them? (yes/no) [yes] "));
if (answer && (!nmc_string_to_bool (answer, &answer_bool, NULL) || !answer_bool)) {
g_free (answer);
@ -3411,6 +3412,17 @@ do_questionnaire_bridge (char **stp, char **priority, char **fwd_delay,
}
} while (once_more);
}
if (!*mac) {
do {
*mac = nmc_get_user_input (_("MAC [none]: "));
once_more = !check_and_convert_mac (*mac, NULL, ARPHRD_ETHER, "mac", &error);
if (once_more) {
printf ("%s\n", error->message);
g_clear_error (&error);
g_free (*mac);
}
} while (once_more);
}
g_free (answer);
return;
@ -4562,12 +4574,16 @@ cleanup_team_slave:
gboolean stp_bool;
unsigned long stp_prio_int, fwd_delay_int, hello_time_int,
max_age_int, ageing_time_int;
const char *mac_c = NULL;
char *mac = NULL;
GByteArray *mac_array = NULL;
nmc_arg_t exp_args[] = { {"stp", TRUE, &stp_c, FALSE},
{"priority", TRUE, &priority_c, FALSE},
{"forward-delay", TRUE, &fwd_delay_c, FALSE},
{"hello-time", TRUE, &hello_time_c, FALSE},
{"max-age", TRUE, &max_age_c, FALSE},
{"ageing-time", TRUE, &ageing_time_c, FALSE},
{"mac", TRUE, &mac_c, FALSE},
{NULL} };
if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
@ -4580,9 +4596,10 @@ cleanup_team_slave:
hello_time = hello_time_c ? g_strdup (hello_time_c) : NULL;
max_age = max_age_c ? g_strdup (max_age_c) : NULL;
ageing_time = ageing_time_c ? g_strdup (ageing_time_c) : NULL;
mac = g_strdup (mac_c);
if (ask)
do_questionnaire_bridge (&stp, &priority, &fwd_delay, &hello_time,
&max_age, &ageing_time);
&max_age, &ageing_time, &mac);
/* Use connection's ifname as 'bridge' ifname if exists, else generate one */
ifname = nm_setting_connection_get_interface_name (s_con);
@ -4629,6 +4646,8 @@ cleanup_team_slave:
if (!bridge_prop_string_to_uint (ageing_time, "ageing-time", NM_TYPE_SETTING_BRIDGE,
NM_SETTING_BRIDGE_AGEING_TIME, &ageing_time_int, error))
goto cleanup_bridge;
if (!check_and_convert_mac (mac, &mac_array, ARPHRD_ETHER, "mac", error))
goto cleanup_bridge;
/* Set bridge options */
g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, bridge_ifname, NULL);
@ -4644,6 +4663,8 @@ cleanup_team_slave:
g_object_set (s_bridge, NM_SETTING_BRIDGE_MAX_AGE, max_age_int, NULL);
if (ageing_time)
g_object_set (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME, ageing_time_int, NULL);
if (mac_array)
g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, mac_array, NULL);
success = TRUE;
cleanup_bridge:
@ -4654,6 +4675,9 @@ cleanup_bridge:
g_free (hello_time);
g_free (max_age);
g_free (ageing_time);
g_free (mac);
if (mac_array)
g_byte_array_free (mac_array, TRUE);
if (!success)
return FALSE;

View file

@ -564,16 +564,18 @@ NmcOutputField nmc_fields_setting_vlan[] = {
NmcOutputField nmc_fields_setting_bridge[] = {
SETTING_FIELD ("name", 8), /* 0 */
SETTING_FIELD (NM_SETTING_BRIDGE_INTERFACE_NAME, 15), /* 1 */
SETTING_FIELD (NM_SETTING_BRIDGE_STP, 5), /* 2 */
SETTING_FIELD (NM_SETTING_BRIDGE_PRIORITY, 6), /* 3 */
SETTING_FIELD (NM_SETTING_BRIDGE_FORWARD_DELAY, 6), /* 4 */
SETTING_FIELD (NM_SETTING_BRIDGE_HELLO_TIME, 6), /* 5 */
SETTING_FIELD (NM_SETTING_BRIDGE_MAX_AGE, 6), /* 6 */
SETTING_FIELD (NM_SETTING_BRIDGE_AGEING_TIME, 6), /* 7 */
SETTING_FIELD (NM_SETTING_BRIDGE_MAC_ADDRESS, 19), /* 2 */
SETTING_FIELD (NM_SETTING_BRIDGE_STP, 5), /* 3 */
SETTING_FIELD (NM_SETTING_BRIDGE_PRIORITY, 6), /* 4 */
SETTING_FIELD (NM_SETTING_BRIDGE_FORWARD_DELAY, 6), /* 5 */
SETTING_FIELD (NM_SETTING_BRIDGE_HELLO_TIME, 6), /* 6 */
SETTING_FIELD (NM_SETTING_BRIDGE_MAX_AGE, 6), /* 7 */
SETTING_FIELD (NM_SETTING_BRIDGE_AGEING_TIME, 6), /* 8 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_BRIDGE_ALL "name"","\
NM_SETTING_BRIDGE_INTERFACE_NAME","\
NM_SETTING_BRIDGE_MAC_ADDRESS","\
NM_SETTING_BRIDGE_STP","\
NM_SETTING_BRIDGE_PRIORITY","\
NM_SETTING_BRIDGE_FORWARD_DELAY","\
@ -1053,6 +1055,7 @@ nmc_property_bond_get_options (NMSetting *setting)
/* --- NM_SETTING_BRIDGE_SETTING_NAME property get functions --- */
DEFINE_GETTER (nmc_property_bridge_get_interface_name, NM_SETTING_BRIDGE_INTERFACE_NAME)
DEFINE_HWADDR_GETTER (nmc_property_bridge_get_mac_address, NM_SETTING_BRIDGE_MAC_ADDRESS)
DEFINE_GETTER (nmc_property_bridge_get_stp, NM_SETTING_BRIDGE_STP)
DEFINE_GETTER (nmc_property_bridge_get_priority, NM_SETTING_BRIDGE_PRIORITY)
DEFINE_GETTER (nmc_property_bridge_get_forward_delay, NM_SETTING_BRIDGE_FORWARD_DELAY)
@ -4926,6 +4929,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (BRIDGE, MAC_ADDRESS),
nmc_property_bridge_get_mac_address,
nmc_property_set_mac,
NULL,
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (BRIDGE, STP),
nmc_property_bridge_get_stp,
nmc_property_set_bool,
@ -7127,12 +7137,13 @@ setting_bridge_details (NMSetting *setting, NmCli *nmc, const char *one_prop)
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
set_val_str (arr, 1, nmc_property_bridge_get_interface_name (setting));
set_val_str (arr, 2, nmc_property_bridge_get_stp (setting));
set_val_str (arr, 3, nmc_property_bridge_get_priority (setting));
set_val_str (arr, 4, nmc_property_bridge_get_forward_delay (setting));
set_val_str (arr, 5, nmc_property_bridge_get_hello_time (setting));
set_val_str (arr, 6, nmc_property_bridge_get_max_age (setting));
set_val_str (arr, 7, nmc_property_bridge_get_ageing_time (setting));
set_val_str (arr, 2, nmc_property_bridge_get_mac_address (setting));
set_val_str (arr, 3, nmc_property_bridge_get_stp (setting));
set_val_str (arr, 4, nmc_property_bridge_get_priority (setting));
set_val_str (arr, 5, nmc_property_bridge_get_forward_delay (setting));
set_val_str (arr, 6, nmc_property_bridge_get_hello_time (setting));
set_val_str (arr, 7, nmc_property_bridge_get_max_age (setting));
set_val_str (arr, 8, nmc_property_bridge_get_ageing_time (setting));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */

View file

@ -220,6 +220,7 @@ global:
nm_setting_bridge_get_forward_delay;
nm_setting_bridge_get_hello_time;
nm_setting_bridge_get_interface_name;
nm_setting_bridge_get_mac_address;
nm_setting_bridge_get_max_age;
nm_setting_bridge_get_priority;
nm_setting_bridge_get_stp;

View file

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <dbus/dbus-glib.h>
#include <glib/gi18n.h>
#include <linux/if_ether.h>
#include "nm-setting-bridge.h"
#include "nm-param-spec-specialized.h"
@ -76,6 +77,7 @@ NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_BRIDGE)
typedef struct {
char * interface_name;
GByteArray *mac_address;
gboolean stp;
guint16 priority;
guint16 forward_delay;
@ -87,6 +89,7 @@ typedef struct {
enum {
PROP_0,
PROP_INTERFACE_NAME,
PROP_MAC_ADDRESS,
PROP_STP,
PROP_PRIORITY,
PROP_FORWARD_DELAY,
@ -127,6 +130,22 @@ nm_setting_bridge_get_interface_name (NMSettingBridge *setting)
return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->interface_name;
}
/**
* nm_setting_bridge_get_mac_address:
* @setting: the #NMSettingBridge
*
* Returns: the #NMSettingBridge:mac-address property of the setting
*
* Since: 0.9.10
**/
const GByteArray *
nm_setting_bridge_get_mac_address (NMSettingBridge *setting)
{
g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), NULL);
return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->mac_address;
}
/**
* nm_setting_bridge_get_stp:
* @setting: the #NMSettingBridge
@ -280,6 +299,15 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
return FALSE;
}
if (priv->mac_address && priv->mac_address->len != ETH_ALEN) {
g_set_error_literal (error,
NM_SETTING_BRIDGE_ERROR,
NM_SETTING_BRIDGE_ERROR_INVALID_PROPERTY,
_("is not a valid MAC address"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MAC_ADDRESS);
return FALSE;
}
if (!check_range (priv->forward_delay,
BR_MIN_FORWARD_DELAY,
BR_MAX_FORWARD_DELAY,
@ -331,6 +359,9 @@ finalize (GObject *object)
g_free (priv->interface_name);
if (priv->mac_address)
g_byte_array_free (priv->mac_address, TRUE);
G_OBJECT_CLASS (nm_setting_bridge_parent_class)->finalize (object);
}
@ -345,6 +376,11 @@ set_property (GObject *object, guint prop_id,
g_free (priv->interface_name);
priv->interface_name = g_value_dup_string (value);
break;
case PROP_MAC_ADDRESS:
if (priv->mac_address)
g_byte_array_free (priv->mac_address, TRUE);
priv->mac_address = g_value_dup_boxed (value);
break;
case PROP_STP:
priv->stp = g_value_get_boolean (value);
break;
@ -380,6 +416,9 @@ get_property (GObject *object, guint prop_id,
case PROP_INTERFACE_NAME:
g_value_set_string (value, nm_setting_bridge_get_interface_name (setting));
break;
case PROP_MAC_ADDRESS:
g_value_set_boxed (value, nm_setting_bridge_get_mac_address (setting));
break;
case PROP_STP:
g_value_set_boolean (value, priv->stp);
break;
@ -435,6 +474,23 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *setting_class)
NULL,
G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE));
/**
* NMSettingBridge:mac-address:
*
* If specified, the MAC address of bridge. When creating a new bridge, this MAC address
* will be set. When matching an existing (outside NetworkManager created) bridge, this
* MAC address must match.
*
* Since: 0.9.10
**/
g_object_class_install_property
(object_class, PROP_MAC_ADDRESS,
_nm_param_spec_specialized (NM_SETTING_BRIDGE_MAC_ADDRESS,
"MAC Address",
"The MAC address of the bridge",
DBUS_TYPE_G_UCHAR_ARRAY,
G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE));
/**
* NMSettingBridge:stp:
*

View file

@ -56,6 +56,7 @@ typedef enum {
GQuark nm_setting_bridge_error_quark (void);
#define NM_SETTING_BRIDGE_INTERFACE_NAME "interface-name"
#define NM_SETTING_BRIDGE_MAC_ADDRESS "mac-address"
#define NM_SETTING_BRIDGE_STP "stp"
#define NM_SETTING_BRIDGE_PRIORITY "priority"
#define NM_SETTING_BRIDGE_FORWARD_DELAY "forward-delay"
@ -83,6 +84,9 @@ NMSetting * nm_setting_bridge_new (void);
const char * nm_setting_bridge_get_interface_name (NMSettingBridge *setting);
NM_AVAILABLE_IN_0_9_10
const GByteArray *nm_setting_bridge_get_mac_address (NMSettingBridge *setting);
gboolean nm_setting_bridge_get_stp (NMSettingBridge *setting);
guint16 nm_setting_bridge_get_priority (NMSettingBridge *setting);

View file

@ -555,6 +555,9 @@ The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disamb
\(en STP maximum message age, in seconds (default: 20)
.IP "\fI[ageing-time <0-1000000>]\fP" 42
\(en the Ethernet MAC address aging time, in seconds (default: 300)
.IP "\fI[mac <MAC address>]\fP" 42
\(en MAC address of the bridge (note: this requires a recent kernel feature,
originally introduced in 3.15 upstream kernel)
.RE
.RS
.TP

View file

@ -102,6 +102,7 @@ check_connection_compatible (NMDevice *device,
{
const char *iface;
NMSettingBridge *s_bridge;
const GByteArray *mac_address;
if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection, error))
return FALSE;
@ -121,6 +122,21 @@ check_connection_compatible (NMDevice *device,
return FALSE;
}
mac_address = nm_setting_bridge_get_mac_address (s_bridge);
if (mac_address) {
guint hw_len;
const guint8 *hw_addr;
hw_addr = nm_device_get_hw_address (device, &hw_len);
if ( !hw_addr
|| hw_len != mac_address->len
|| memcmp (mac_address->data, hw_addr, hw_len) != 0) {
g_set_error (error, NM_BRIDGE_ERROR, NM_BRIDGE_ERROR_CONNECTION_INVALID,
"The bridge mac-address does not match the address of the device.");
return FALSE;
}
}
return TRUE;
}
@ -438,13 +454,22 @@ NMDevice *
nm_device_bridge_new_for_connection (NMConnection *connection)
{
const char *iface;
NMSettingBridge *s_bridge;
const GByteArray *mac_address;
g_return_val_if_fail (connection != NULL, NULL);
iface = nm_connection_get_virtual_iface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
if ( !nm_platform_bridge_add (iface)
s_bridge = nm_connection_get_setting_bridge (connection);
g_return_val_if_fail (s_bridge, NULL);
mac_address = nm_setting_bridge_get_mac_address (s_bridge);
if ( !nm_platform_bridge_add (iface,
mac_address ? mac_address->data : NULL,
mac_address ? mac_address->len : 0)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s",
iface, nm_connection_get_id (connection),

View file

@ -185,7 +185,7 @@ link_added_emit (gpointer user_data)
}
static gboolean
link_add (NMPlatform *platform, const char *name, NMLinkType type)
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
NMFakePlatformLink device;
@ -600,7 +600,7 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint
{
NMFakePlatformLink *device;
if (!link_add (platform, name, NM_LINK_TYPE_VLAN))
if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0))
return FALSE;
device = link_get (platform, link_get_ifindex (platform, name));
@ -651,7 +651,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
g_return_val_if_fail (parent_device != NULL, FALSE);
name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key);
success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND);
success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0);
g_free (name);
return success;
@ -1232,15 +1232,15 @@ static gboolean
setup (NMPlatform *platform)
{
/* skip zero element */
link_add (platform, NULL, NM_LINK_TYPE_NONE);
link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0);
/* add loopback interface */
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK);
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0);
/* add some ethernets */
link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET);
link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET);
link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET);
link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0);
link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0);
link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0);
return TRUE;
}

View file

@ -1871,9 +1871,10 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type)
}
static gboolean
link_add (NMPlatform *platform, const char *name, NMLinkType type)
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
{
int r;
struct nl_object *link;
if (type == NM_LINK_TYPE_BOND) {
/* When the kernel loads the bond module, either via explicit modprobe
@ -1891,7 +1892,15 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type)
debug ("link: add link '%s' of type '%s' (%d)",
name, type_to_string (type), (int) type);
return add_object (platform, build_rtnl_link (0, name, type));
link = build_rtnl_link (0, name, type);
g_assert ( (address != NULL) ^ (address_len == 0) );
if (address) {
auto_nl_addr struct nl_addr *nladdr = _nm_nl_addr_build (AF_LLC, address, address_len);
rtnl_link_set_addr ((struct rtnl_link *) link, nladdr);
}
return add_object (platform, link);
}
static struct rtnl_link *

View file

@ -443,18 +443,21 @@ nm_platform_link_get_all (void)
* nm_platform_link_add:
* @name: Interface name
* @type: Interface type
* @address: (allow-none): set the mac address of the link
* @address_len: the length of the @address
*
* Add a software interface. Sets platform->error to NM_PLATFORM_ERROR_EXISTS
* if interface is already already exists. Any link-added signal will be
* emitted from an idle handler and not within this function.
*/
static gboolean
nm_platform_link_add (const char *name, NMLinkType type)
nm_platform_link_add (const char *name, NMLinkType type, const void *address, size_t address_len)
{
reset_error ();
g_return_val_if_fail (name, FALSE);
g_return_val_if_fail (klass->link_add, FALSE);
g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE);
if (nm_platform_link_exists (name)) {
debug ("link: already exists");
@ -462,7 +465,7 @@ nm_platform_link_add (const char *name, NMLinkType type)
return FALSE;
}
return klass->link_add (platform, name, type);
return klass->link_add (platform, name, type, address, address_len);
}
/**
@ -477,7 +480,7 @@ nm_platform_dummy_add (const char *name)
g_return_val_if_fail (name, FALSE);
debug ("link: adding dummy '%s'", name);
return nm_platform_link_add (name, NM_LINK_TYPE_DUMMY);
return nm_platform_link_add (name, NM_LINK_TYPE_DUMMY, NULL, 0);
}
/**
@ -985,14 +988,16 @@ nm_platform_link_get_master (int slave)
/**
* nm_platform_bridge_add:
* @name: New interface name
* @address: (allow-none): set the mac address of the new bridge
* @address_len: the length of the @address
*
* Create a software bridge.
*/
gboolean
nm_platform_bridge_add (const char *name)
nm_platform_bridge_add (const char *name, const void *address, size_t address_len)
{
debug ("link: adding bridge '%s'", name);
return nm_platform_link_add (name, NM_LINK_TYPE_BRIDGE);
return nm_platform_link_add (name, NM_LINK_TYPE_BRIDGE, address, address_len);
}
/**
@ -1005,7 +1010,7 @@ gboolean
nm_platform_bond_add (const char *name)
{
debug ("link: adding bond '%s'", name);
return nm_platform_link_add (name, NM_LINK_TYPE_BOND);
return nm_platform_link_add (name, NM_LINK_TYPE_BOND, NULL, 0);
}
/**
@ -1018,7 +1023,7 @@ gboolean
nm_platform_team_add (const char *name)
{
debug ("link: adding team '%s'", name);
return nm_platform_link_add (name, NM_LINK_TYPE_TEAM);
return nm_platform_link_add (name, NM_LINK_TYPE_TEAM, NULL, 0);
}
/**

View file

@ -347,7 +347,7 @@ typedef struct {
char * (*sysctl_get) (NMPlatform *, const char *path);
GArray *(*link_get_all) (NMPlatform *);
gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type);
gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len);
gboolean (*link_delete) (NMPlatform *, int ifindex);
int (*link_get_ifindex) (NMPlatform *, const char *name);
const char *(*link_get_name) (NMPlatform *, int ifindex);
@ -479,7 +479,7 @@ gint64 nm_platform_sysctl_get_int_checked (const char *path, guint base, gint64
GArray *nm_platform_link_get_all (void);
gboolean nm_platform_dummy_add (const char *name);
gboolean nm_platform_bridge_add (const char *name);
gboolean nm_platform_bridge_add (const char *name, const void *address, size_t address_len);
gboolean nm_platform_bond_add (const char *name);
gboolean nm_platform_team_add (const char *name);
gboolean nm_platform_link_exists (const char *name);

View file

@ -96,7 +96,7 @@ do_dummy_add (char **argv)
static gboolean
do_bridge_add (char **argv)
{
return nm_platform_bridge_add (argv[0]);
return nm_platform_bridge_add (argv[0], NULL, 0);
}
static gboolean

View file

@ -89,7 +89,7 @@ software_add (NMLinkType link_type, const char *name)
case NM_LINK_TYPE_DUMMY:
return nm_platform_dummy_add (name);
case NM_LINK_TYPE_BRIDGE:
return nm_platform_bridge_add (name);
return nm_platform_bridge_add (name, NULL, 0);
case NM_LINK_TYPE_BOND:
{
gboolean bond0_exists = nm_platform_link_exists ("bond0");
@ -111,7 +111,7 @@ software_add (NMLinkType link_type, const char *name)
/* Don't call link_callback for the bridge interface */
parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
if (nm_platform_bridge_add (PARENT_NAME))
if (nm_platform_bridge_add (PARENT_NAME, NULL, 0))
wait_signal (parent_added);
free_signal (parent_added);

View file

@ -4508,6 +4508,7 @@ make_bridge_setting (shvarFile *ifcfg,
guint32 u;
gboolean stp = FALSE;
gboolean stp_set = FALSE;
GByteArray *array = NULL;
s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
@ -4520,6 +4521,16 @@ make_bridge_setting (shvarFile *ifcfg,
g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, value, NULL);
g_free (value);
if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &array, error)) {
if (array) {
g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, array, NULL);
g_byte_array_free (array, TRUE);
}
} else {
PARSE_WARNING ("%s", (*error)->message);
g_clear_error (error);
}
value = svGetValue (ifcfg, "STP", FALSE);
if (value) {
if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {

View file

@ -5,3 +5,4 @@ BOOTPROTO=dhcp
STP=on
DELAY=0
BRIDGING_OPTS="priority=32744 hello_time=7 max_age=39 ageing_time=235352"
MACADDR=00:16:41:11:22:33

View file

@ -12056,6 +12056,8 @@ test_read_bridge_main (void)
{
NMConnection *connection;
NMSettingBridge *s_bridge;
const GByteArray *array;
char expected_mac_address[ETH_ALEN] = { 0x00, 0x16, 0x41, 0x11, 0x22, 0x33 };
char *unmanaged = NULL;
char *keyfile = NULL;
char *routefile = NULL;
@ -12088,6 +12090,11 @@ test_read_bridge_main (void)
g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7);
g_assert_cmpuint (nm_setting_bridge_get_max_age (s_bridge), ==, 39);
g_assert_cmpuint (nm_setting_bridge_get_ageing_time (s_bridge), ==, 235352);
/* MAC address */
array = nm_setting_bridge_get_mac_address (s_bridge);
g_assert (array);
g_assert_cmpint (array->len, ==, ETH_ALEN);
g_assert (memcmp (array->data, &expected_mac_address[0], ETH_ALEN) == 0);
g_free (unmanaged);
g_free (keyfile);
@ -12110,6 +12117,8 @@ test_write_bridge_main (void)
const guint32 gw = htonl (0x01010101);
const guint32 prefix = 24;
NMIP4Address *addr;
static unsigned char bridge_mac[] = { 0x31, 0x33, 0x33, 0x37, 0xbe, 0xcd };
GByteArray *mac_array;
gboolean success;
GError *error = NULL;
char *testfile = NULL;
@ -12141,9 +12150,13 @@ test_write_bridge_main (void)
g_assert (s_bridge);
nm_connection_add_setting (connection, NM_SETTING (s_bridge));
mac_array = g_byte_array_sized_new (sizeof (bridge_mac));
g_byte_array_append (mac_array, bridge_mac, sizeof (bridge_mac));
g_object_set (s_bridge,
NM_SETTING_BRIDGE_INTERFACE_NAME, "br0",
NM_SETTING_BRIDGE_MAC_ADDRESS, mac_array,
NULL);
g_byte_array_free (mac_array, TRUE);
/* IP4 setting */
s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();

View file

@ -1379,6 +1379,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error
const char *iface;
guint32 i;
GString *opts;
const GByteArray *mac;
char *s;
s_bridge = nm_connection_get_setting_bridge (connection);
@ -1398,6 +1399,11 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error
svSetValue (ifcfg, "BRIDGING_OPTS", NULL, FALSE);
svSetValue (ifcfg, "STP", "no", FALSE);
svSetValue (ifcfg, "DELAY", NULL, FALSE);
svSetValue (ifcfg, "MACADDR", NULL, FALSE);
mac = nm_setting_bridge_get_mac_address (s_bridge);
if (mac)
svSetValue_free (ifcfg, "MACADDR", nm_utils_hwaddr_ntoa_len (mac->data, mac->len), FALSE);
/* Bridge options */
opts = g_string_sized_new (32);

View file

@ -901,6 +901,10 @@ static KeyParser key_parsers[] = {
NM_SETTING_CONNECTION_TYPE,
TRUE,
setting_alias_parser },
{ NM_SETTING_BRIDGE_SETTING_NAME,
NM_SETTING_BRIDGE_MAC_ADDRESS,
TRUE,
mac_address_parser_ETHER },
{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_ADDRESSES,
FALSE,

View file

@ -774,6 +774,9 @@ static KeyWriter key_writers[] = {
{ NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_TYPE,
setting_alias_writer },
{ NM_SETTING_BRIDGE_SETTING_NAME,
NM_SETTING_BRIDGE_MAC_ADDRESS,
mac_address_writer },
{ NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_ADDRESSES,
ip4_addr_writer },