diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index ab16bcdca0..595fa1a1e0 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -389,6 +389,37 @@ link_get_master (NMPlatform *platform, int slave) return device->master; } +static gboolean +master_set_option (NMPlatform *platform, int master, const char *option, const char *value) +{ + auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option); + + return sysctl_set (platform, path, value); +} + +static char * +master_get_option (NMPlatform *platform, int master, const char *option) +{ + auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option); + + return sysctl_get (platform, path); +} + +static gboolean +slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) +{ + auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); + + return sysctl_set (platform, path, value); +} + +static char * +slave_get_option (NMPlatform *platform, int slave, const char *option) +{ + auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); + + return sysctl_get (platform, path); +} /******************************************************************/ @@ -831,6 +862,10 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; platform_class->link_get_master = link_get_master; + platform_class->master_set_option = master_set_option; + platform_class->master_get_option = master_get_option; + platform_class->slave_set_option = slave_set_option; + platform_class->slave_get_option = slave_get_option; platform_class->ip4_address_get_all = ip4_address_get_all; platform_class->ip6_address_get_all = ip6_address_get_all; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a0b7793c66..89af928841 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1072,6 +1072,88 @@ link_get_master (NMPlatform *platform, int slave) return result; } +static char * +link_option_path (int master, const char *category, const char *option) +{ + const char *name = nm_platform_link_get_name (master); + + if (!name || !category || !option) + return NULL; + + return g_strdup_printf ("/sys/class/net/%s/%s/%s", name, category, option); +} + +static gboolean +link_set_option (int master, const char *category, const char *option, const char *value) +{ + auto_g_free char *path = link_option_path (master, category, option); + + return path && nm_platform_sysctl_set (path, value); +} + +static char * +link_get_option (int master, const char *category, const char *option) +{ + auto_g_free char *path = link_option_path (master, category, option); + + return path ? nm_platform_sysctl_get (path) : NULL; +} + +static const char * +master_category (NMPlatform *platform, int master) +{ + switch (link_get_type (platform, master)) { + case NM_LINK_TYPE_BRIDGE: + return "bridge"; + case NM_LINK_TYPE_BOND: + return "bonding"; + default: + g_assert_not_reached (); + } +} + +static const char * +slave_category (NMPlatform *platform, int slave) +{ + int master = link_get_master (platform, slave); + + if (master) { + platform->error = NM_PLATFORM_ERROR_NOT_SLAVE; + return NULL; + } + + switch (link_get_type (platform, master)) { + case NM_LINK_TYPE_BRIDGE: + return "brport"; + default: + g_assert_not_reached (); + } +} + +static gboolean +master_set_option (NMPlatform *platform, int master, const char *option, const char *value) +{ + return link_set_option (master, master_category (platform, master), option, value); +} + +static char * +master_get_option (NMPlatform *platform, int master, const char *option) +{ + return link_get_option (master, master_category (platform, master), option); +} + +static gboolean +slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) +{ + return link_set_option (slave, slave_category (platform, slave), option, value); +} + +static char * +slave_get_option (NMPlatform *platform, int slave, const char *option) +{ + return link_get_option (slave, slave_category (platform, slave), option); +} + /******************************************************************/ static int @@ -1539,6 +1621,10 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; platform_class->link_get_master = link_get_master; + platform_class->master_set_option = master_set_option; + platform_class->master_get_option = master_get_option; + platform_class->slave_set_option = slave_set_option; + platform_class->slave_get_option = slave_get_option; platform_class->ip4_address_get_all = ip4_address_get_all; platform_class->ip6_address_get_all = ip6_address_get_all; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 727eda39a8..016c5f91bd 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -663,6 +663,56 @@ nm_platform_team_add (const char *name) return nm_platform_link_add (name, NM_LINK_TYPE_TEAM); } +gboolean +nm_platform_master_set_option (int ifindex, const char *option, const char *value) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (klass->master_set_option, FALSE); + + return klass->master_set_option (platform, ifindex, option, value); +} + +char * +nm_platform_master_get_option (int ifindex, const char *option) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (klass->master_set_option, FALSE); + + return klass->master_get_option (platform, ifindex, option); +} + +gboolean +nm_platform_slave_set_option (int ifindex, const char *option, const char *value) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (klass->slave_set_option, FALSE); + + return klass->slave_set_option (platform, ifindex, option, value); +} + +char * +nm_platform_slave_get_option (int ifindex, const char *option) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (option, FALSE); + g_return_val_if_fail (klass->slave_set_option, FALSE); + + return klass->slave_get_option (platform, ifindex, option); +} + /******************************************************************/ GArray * diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 0110271849..5f9cf06f65 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -149,6 +149,10 @@ typedef struct { gboolean (*link_enslave) (NMPlatform *, int master, int slave); gboolean (*link_release) (NMPlatform *, int master, int slave); gboolean (*link_get_master) (NMPlatform *, int slave); + gboolean (*master_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); + char * (*master_get_option) (NMPlatform *, int ifindex, const char *option); + gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); + char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex); GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex); @@ -256,6 +260,10 @@ gboolean nm_platform_link_supports_vlans (int ifindex); gboolean nm_platform_link_enslave (int master, int slave); gboolean nm_platform_link_release (int master, int slave); int nm_platform_link_get_master (int slave); +gboolean nm_platform_master_set_option (int ifindex, const char *option, const char *value); +char *nm_platform_master_get_option (int ifindex, const char *option); +gboolean nm_platform_slave_set_option (int ifindex, const char *option, const char *value); +char *nm_platform_slave_get_option (int ifindex, const char *option); GArray *nm_platform_ip4_address_get_all (int ifindex); GArray *nm_platform_ip6_address_get_all (int ifindex); @@ -282,4 +290,16 @@ gboolean nm_platform_ip4_route_exists (int ifindex, gboolean nm_platform_ip6_route_exists (int ifindex, struct in6_addr network, int plen, struct in6_addr gateway, int metric); +#define auto_g_free __attribute__((cleanup(put_g_free))) +static void __attribute__((unused)) +put_g_free (void *ptr) +{ + gpointer *object = ptr; + + if (object && *object) { + g_free (*object); + *object = NULL; + } +} + #endif /* NM_PLATFORM_H */ diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 9c46547189..049dc97d98 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -120,6 +120,7 @@ test_slave (int master, int type, SignalData *link_added, SignalData *master_cha { int ifindex; SignalData *link_changed = add_signal ("link-changed", link_callback); + char *value; g_assert (virtual_add (type, SLAVE_NAME, link_added, link_changed)); ifindex = nm_platform_link_get_ifindex (SLAVE_NAME); @@ -179,6 +180,20 @@ test_slave (int master, int type, SignalData *link_added, SignalData *master_cha accept_signal (link_changed); accept_signal (master_changed); + /* Set slave option */ + switch (type) { + case NM_LINK_TYPE_BRIDGE: + g_assert (nm_platform_slave_set_option (ifindex, "priority", "789")); + no_error (); + value = nm_platform_slave_get_option (ifindex, "priority"); + no_error (); + g_assert (!g_strcmp0 (value, "789")); + g_free (value); + break; + default: + break; + } + /* Release */ g_assert (nm_platform_link_release (master, ifindex)); g_assert (nm_platform_link_get_master (ifindex) == 0); no_error (); @@ -201,6 +216,7 @@ static void test_virtual (NMLinkType link_type) { int ifindex; + char *value; SignalData *link_added = add_signal ("link-added", link_callback); SignalData *link_changed = add_signal ("link-changed", link_callback); @@ -228,6 +244,29 @@ test_virtual (NMLinkType link_type) g_assert (nm_platform_link_uses_arp (ifindex)); accept_signal (link_changed); + /* Set master option */ + switch (link_type) { + case NM_LINK_TYPE_BRIDGE: + g_assert (nm_platform_master_set_option (ifindex, "forward_delay", "789")); + no_error (); + value = nm_platform_master_get_option (ifindex, "forward_delay"); + no_error (); + g_assert (!g_strcmp0 (value, "789")); + g_free (value); + break; + case NM_LINK_TYPE_BOND: + g_assert (nm_platform_master_set_option (ifindex, "mode", "active-backup")); + no_error (); + value = nm_platform_master_get_option (ifindex, "mode"); + no_error (); + /* When reading back, the output looks slightly different. */ + g_assert (g_str_has_prefix (value, "active-backup")); + g_free (value); + break; + default: + break; + } + /* Enslave and release */ switch (link_type) { case NM_LINK_TYPE_BRIDGE: