summary refs log tree commit diff
path: root/src/core/devices/nm-device-bond.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-08-16 18:24:19 +0200
committerMichael Biebl <biebl@debian.org>2022-08-16 18:24:19 +0200
commit0018d1f3cf71d680d7b6bceda55a5717244d8b26 (patch)
treea058f1d106d172d3354179437ef034c9355cdf9c /src/core/devices/nm-device-bond.c
parent6accbd3ec0e42d8633bbde4d47ed7bfe854e7e0b (diff)
New upstream version 1.39.90 upstream/1.39.90
Diffstat (limited to 'src/core/devices/nm-device-bond.c')
-rw-r--r--src/core/devices/nm-device-bond.c209
1 files changed, 159 insertions, 50 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c
index 16896d57..41473abe 100644
--- a/src/core/devices/nm-device-bond.c
+++ b/src/core/devices/nm-device-bond.c
@@ -9,6 +9,8 @@
 
 #include <stdlib.h>
 #include <net/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
 
 #include "NetworkManagerUtils.h"
 #include "nm-device-private.h"
@@ -16,6 +18,7 @@
 #include "nm-device-factory.h"
 #include "libnm-core-aux-intern/nm-libnm-core-utils.h"
 #include "libnm-core-intern/nm-core-internal.h"
+#include "nm-manager.h"
 #include "nm-setting-bond-port.h"
 
 #define _NMLOG_DEVICE_TYPE NMDeviceBond
@@ -312,7 +315,7 @@ set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *op
     NMDeviceBond *self = NM_DEVICE_BOND(device);
     const char   *value;
 
-    value = nm_setting_bond_get_option_or_default(s_bond, opt);
+    value = nm_setting_bond_get_option_normalized(s_bond, opt);
     if (!value) {
         if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt))
             _LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt);
@@ -346,54 +349,147 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond)
     set_arp_targets(
         device,
         cur_arp_ip_target,
-        nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
+        nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
 }
 
-static gboolean
-apply_bonding_config(NMDeviceBond *self)
+static guint8
+_bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_MAX_ARP_TARGETS])
 {
-    NMDevice      *device = NM_DEVICE(self);
-    NMSettingBond *s_bond;
-    NMBondMode     mode;
-    const char    *mode_str;
-    gs_free char  *device_bond_mode = NULL;
+    gs_free const char **ip = NULL;
+    in_addr_t            in_a;
+    int                  i;
+    int                  added = 0;
 
-    s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND);
-    g_return_val_if_fail(s_bond, FALSE);
+    ip = nm_utils_bond_option_arp_ip_targets_split(value);
 
-    mode_str = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
-    mode     = _nm_setting_bond_mode_from_string(mode_str);
-    g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE);
+    if (!ip)
+        return added;
 
-    /* Set mode first, as some other options (e.g. arp_interval) are valid
-     * only for certain modes.
-     */
-    device_bond_mode = nm_platform_sysctl_master_get_option(nm_device_get_platform(device),
-                                                            nm_device_get_ifindex(device),
-                                                            NM_SETTING_BOND_OPTION_MODE);
-    /* Need to release all slaves before we can change bond mode */
-    if (!nm_streq0(device_bond_mode, mode_str))
-        nm_device_master_release_slaves_all(device);
+    for (i = 0; ip[i]; i++) {
+        if (added > NM_BOND_MAX_ARP_TARGETS - 1)
+            break;
+        if (!nm_utils_parse_inaddr_bin(AF_INET, ip[i], NULL, &in_a))
+            nm_assert_not_reached(); /* verify() already validated the IP addresses */
+
+        out[added++] = in_a;
+    }
+    return added;
+}
 
-    set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_MODE);
+static int
+_setting_bond_primary_opt_as_ifindex(NMSettingBond *s_bond)
+{
+    const char *primary_str;
+    int         ifindex = 0;
 
-    set_bond_arp_ip_targets(device, s_bond);
+    primary_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
 
-    set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_APPLY_SUBSET));
-    return TRUE;
+    if (primary_str != NULL)
+        ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, primary_str);
+
+    return ifindex;
+}
+
+static void
+_platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *props)
+{
+    const char *opt_value;
+
+    *props = (NMPlatformLnkBond){
+        .mode = _nm_setting_bond_mode_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE)),
+        .primary   = _setting_bond_primary_opt_as_ifindex(s_bond),
+        .miimon    = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON),
+        .updelay   = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_UPDELAY),
+        .downdelay = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY),
+        .arp_interval =
+            _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL),
+        .resend_igmp =
+            _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP),
+        .min_links = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS),
+        .lp_interval =
+            _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL),
+        .packets_per_port =
+            _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE),
+        .peer_notif_delay =
+            _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY),
+        .arp_all_targets = _nm_setting_bond_arp_all_targets_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS)),
+        .arp_validate = _nm_setting_bond_arp_validate_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE)),
+        .ad_actor_sys_prio =
+            _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO),
+        .ad_user_port_key =
+            _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY),
+        .primary_reselect = _nm_setting_bond_primary_reselect_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT)),
+        .fail_over_mac = _nm_setting_bond_fail_over_mac_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC)),
+        .xmit_hash_policy = _nm_setting_bond_xmit_hash_policy_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY)),
+        .num_grat_arp =
+            _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP),
+        .all_ports_active =
+            _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE),
+        .lacp_rate = _nm_setting_bond_lacp_rate_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_LACP_RATE)),
+        .ad_select = _nm_setting_bond_ad_select_from_string(
+            nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_SELECT)),
+    };
+
+    nm_ether_addr_from_string(
+        &props->ad_actor_system,
+        nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM));
+
+    opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER);
+    if (opt_value != NULL)
+        props->use_carrier = _nm_utils_ascii_str_to_bool(opt_value, FALSE);
+
+    opt_value =
+        nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB);
+    if (opt_value != NULL)
+        props->tlb_dynamic_lb = _nm_utils_ascii_str_to_bool(opt_value, FALSE);
+
+    opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
+    if (opt_value != NULL)
+        props->arp_ip_targets_num =
+            _bond_arp_ip_target_to_platform(opt_value, props->arp_ip_target);
+
+    props->miimon_has           = !props->arp_interval && !props->arp_validate;
+    props->updelay_has          = props->miimon_has && props->miimon;
+    props->downdelay_has        = props->miimon_has && props->miimon;
+    props->peer_notif_delay_has = (props->miimon || props->arp_interval) && props->peer_notif_delay;
+    props->arp_all_targets_has  = props->arp_interval && props->arp_all_targets;
+    props->resend_igmp_has      = props->resend_igmp != 1;
+    props->lp_interval          = props->lp_interval != 1;
+    props->tlb_dynamic_lb_has   = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB);
 }
 
 static NMActStageReturn
 act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
 {
-    NMDeviceBond    *self = NM_DEVICE_BOND(device);
-    NMActStageReturn ret  = NM_ACT_STAGE_RETURN_SUCCESS;
+    NMActStageReturn  ret = NM_ACT_STAGE_RETURN_SUCCESS;
+    NMConnection     *connection;
+    NMSettingBond    *s_bond;
+    NMPlatformLnkBond props;
+    int               r;
+    int               ifindex = nm_device_get_ifindex(device);
+
+    connection = nm_device_get_applied_connection(device);
+    g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE);
+
+    s_bond = nm_connection_get_setting_bond(connection);
+    g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE);
+
+    _platform_lnk_bond_init_from_setting(s_bond, &props);
 
     /* Interface must be down to set bond options */
     nm_device_take_down(device, TRUE);
-    if (!apply_bonding_config(self))
+    r = nm_platform_link_bond_change(nm_device_get_platform(device), ifindex, &props);
+    if (r < 0) {
         ret = NM_ACT_STAGE_RETURN_FAILURE;
-    else {
+        NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+    } else {
         if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE))
             ret = NM_ACT_STAGE_RETURN_FAILURE;
     }
@@ -424,8 +520,14 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_
                                          queue_id_str);
 }
 
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice                  *device,
+            NMDevice                  *port,
+            NMConnection              *connection,
+            gboolean                   configure,
+            GCancellable              *cancellable,
+            NMDeviceAttachPortCallback callback,
+            gpointer                   user_data)
 {
     NMDeviceBond      *self = NM_DEVICE_BOND(device);
     NMSettingBondPort *s_port;
@@ -442,7 +544,7 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
         nm_device_bring_up(port, TRUE, NULL);
 
         if (!success) {
-            _LOGI(LOGD_BOND, "assigning bond port %s: failed", nm_device_get_ip_iface(port));
+            _LOGI(LOGD_BOND, "attaching bond port %s: failed", nm_device_get_ip_iface(port));
             return FALSE;
         }
 
@@ -450,15 +552,15 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
 
         commit_port_options(device, port, s_port);
 
-        _LOGI(LOGD_BOND, "assigned bond port %s", nm_device_get_ip_iface(port));
+        _LOGI(LOGD_BOND, "attached bond port %s", nm_device_get_ip_iface(port));
     } else
-        _LOGI(LOGD_BOND, "bond port %s was assigned", nm_device_get_ip_iface(port));
+        _LOGI(LOGD_BOND, "bond port %s was attached", nm_device_get_ip_iface(port));
 
     return TRUE;
 }
 
 static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
 {
     NMDeviceBond *self = NM_DEVICE_BOND(device);
     gboolean      success;
@@ -472,10 +574,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
             configure = FALSE;
     }
 
-    ifindex_slave = nm_device_get_ip_ifindex(slave);
+    ifindex_slave = nm_device_get_ip_ifindex(port);
 
     if (ifindex_slave <= 0)
-        _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave));
+        _LOGD(LOGD_BOND, "bond port %s is already detached", nm_device_get_ip_iface(port));
 
     if (configure) {
         NMConnection   *applied;
@@ -490,9 +592,9 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
                                                ifindex_slave);
 
             if (success) {
-                _LOGI(LOGD_BOND, "released bond slave %s", nm_device_get_ip_iface(slave));
+                _LOGI(LOGD_BOND, "detached bond port %s", nm_device_get_ip_iface(port));
             } else {
-                _LOGW(LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface(slave));
+                _LOGW(LOGD_BOND, "failed to detach bond port %s", nm_device_get_ip_iface(port));
             }
         }
 
@@ -512,12 +614,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
          * other state is noticed by the now-released slave.
          */
         if (ifindex_slave > 0) {
-            if (!nm_device_bring_up(slave, TRUE, NULL))
-                _LOGW(LOGD_BOND, "released bond slave could not be brought up.");
+            if (!nm_device_bring_up(port, TRUE, NULL))
+                _LOGW(LOGD_BOND, "detached bond port could not be brought up.");
         }
     } else {
         if (ifindex_slave > 0) {
-            _LOGI(LOGD_BOND, "bond slave %s was released", nm_device_get_ip_iface(slave));
+            _LOGI(LOGD_BOND, "bond port %s was detached", nm_device_get_ip_iface(port));
         }
     }
 }
@@ -529,12 +631,19 @@ create_and_realize(NMDevice              *device,
                    const NMPlatformLink **out_plink,
                    GError               **error)
 {
-    const char *iface = nm_device_get_iface(device);
-    int         r;
+    const char       *iface = nm_device_get_iface(device);
+    NMSettingBond    *s_bond;
+    NMPlatformLnkBond props;
+    int               r;
 
     g_assert(iface);
 
-    r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, out_plink);
+    s_bond = nm_connection_get_setting_bond(connection);
+    nm_assert(s_bond);
+
+    _platform_lnk_bond_init_from_setting(s_bond, &props);
+
+    r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, &props, out_plink);
     if (r < 0) {
         g_set_error(error,
                     NM_DEVICE_ERROR,
@@ -612,7 +721,7 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne
     s_bond = nm_connection_get_setting_bond(con_new);
     g_return_if_fail(s_bond);
 
-    value = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
+    value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
     mode  = _nm_setting_bond_mode_from_string(value);
     g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN);
 
@@ -663,8 +772,8 @@ nm_device_bond_class_init(NMDeviceBondClass *klass)
     device_class->create_and_realize = create_and_realize;
     device_class->act_stage1_prepare = act_stage1_prepare;
     device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
-    device_class->enslave_slave      = enslave_slave;
-    device_class->release_slave      = release_slave;
+    device_class->attach_port        = attach_port;
+    device_class->detach_port        = detach_port;
     device_class->can_reapply_change = can_reapply_change;
     device_class->reapply_connection = reapply_connection;
 }