diff options
| author | Michael Biebl <biebl@debian.org> | 2022-10-18 11:56:48 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2022-10-18 11:56:48 +0200 |
| commit | 9f101839d9e64df832e9e43c5181887369c46a7e (patch) | |
| tree | 3e23589a9d4e9e7c32ce41b634ccf26af3f0d45e /src | |
| parent | ab0efddcdb48d800e2f938da54cfe3074640792e (diff) | |
New upstream version 1.40.2 upstream/1.40.2
Diffstat (limited to 'src')
40 files changed, 1024 insertions, 412 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 44bb316d..3e083de4 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -395,61 +395,57 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p { const char *opt_value; +#define _v_fcn(fcn, s_bond, opt) (fcn(nm_setting_bond_get_option_normalized((s_bond), (opt)))) +#define _v_u8(s_bond, opt) _nm_setting_bond_opt_value_as_u8((s_bond), (opt)) +#define _v_u16(s_bond, opt) _nm_setting_bond_opt_value_as_u16((s_bond), (opt)) +#define _v_u32(s_bond, opt) _nm_setting_bond_opt_value_as_u32((s_bond), (opt)) +#define _v_intbool(s_bond, opt) _nm_setting_bond_opt_value_as_intbool((s_bond), (opt)) + *props = (NMPlatformLnkBond){ - .mode = _nm_setting_bond_mode_from_string( - nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE)), + .mode = _v_fcn(_nm_setting_bond_mode_from_string, 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)), + .miimon = _v_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON), + .updelay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_UPDELAY), + .downdelay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY), + .arp_interval = _v_u32(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL), + .resend_igmp = _v_u32(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP), + .min_links = _v_u32(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS), + .lp_interval = _v_u32(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL), + .packets_per_port = _v_u32(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE), + .peer_notif_delay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY), + .arp_all_targets = _v_fcn(_nm_setting_bond_arp_all_targets_from_string, + s_bond, + NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS), + .arp_validate = _v_fcn(_nm_setting_bond_arp_validate_from_string, + s_bond, + NM_SETTING_BOND_OPTION_ARP_VALIDATE), + .ad_actor_sys_prio = _v_u16(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO), + .ad_user_port_key = _v_u16(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY), + .primary_reselect = _v_fcn(_nm_setting_bond_primary_reselect_from_string, + s_bond, + NM_SETTING_BOND_OPTION_PRIMARY_RESELECT), + .fail_over_mac = _v_fcn(_nm_setting_bond_fail_over_mac_from_string, + s_bond, + NM_SETTING_BOND_OPTION_FAIL_OVER_MAC), + .xmit_hash_policy = _v_fcn(_nm_setting_bond_xmit_hash_policy_from_string, + s_bond, + NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY), + .num_grat_arp = _v_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP), + .all_ports_active = _v_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE), + .lacp_rate = _v_fcn(_nm_setting_bond_lacp_rate_from_string, + s_bond, + NM_SETTING_BOND_OPTION_LACP_RATE), + .ad_select = _v_fcn(_nm_setting_bond_ad_select_from_string, + s_bond, + NM_SETTING_BOND_OPTION_AD_SELECT), + .use_carrier = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER), + .tlb_dynamic_lb = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB), }; 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 = @@ -459,7 +455,6 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p 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_has = props->lp_interval != 1; props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); @@ -493,6 +488,10 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) ret = NM_ACT_STAGE_RETURN_FAILURE; } + + /* This is a workaround because netlink do not support ifname as primary */ + set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); + nm_device_bring_up(device, TRUE, NULL); return ret; diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h index b54aed6a..31424d5c 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -89,7 +89,10 @@ nm_device_devip_set_state(NMDevice *self, nm_assert(NM_IS_DEVICE(self)); nm_assert_addr_family_or_unspec(addr_family); nm_assert(!l3cd || NM_IS_L3_CONFIG_DATA(l3cd)); - nm_assert(NM_IN_SET(ip_state, NM_DEVICE_IP_STATE_PENDING, NM_DEVICE_IP_STATE_READY)); + nm_assert(NM_IN_SET(ip_state, + NM_DEVICE_IP_STATE_NONE, + NM_DEVICE_IP_STATE_PENDING, + NM_DEVICE_IP_STATE_READY)); nm_device_devip_set_state_full(self, addr_family, ip_state, l3cd, NM_DEVICE_STATE_REASON_NONE); } diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index 63dfd8bb..c3482e78 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -101,8 +101,8 @@ create_and_realize(NMDevice *device, peer = nm_setting_veth_get_peer(s_veth); peer_device = nm_manager_get_device(NM_MANAGER_GET, peer, NM_DEVICE_TYPE_VETH); if (peer_device) { - /* The veth device and its peer already exist. No need to create it again. */ - if (nm_streq0(nm_device_get_iface(nm_device_parent_get_device(peer_device)), iface)) + if (nm_device_parent_get_device(peer_device)) + /* The veth device and its peer already exist. No need to create it again. */ return TRUE; } diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index d63b902b..6be9bc7c 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -96,6 +96,8 @@ #define NM_DEVICE_AUTH_RETRIES_INFINITY -2 #define NM_DEVICE_AUTH_RETRIES_DEFAULT 3 +#define AUTOCONNECT_RESET_RETRIES_TIMER 300 + /*****************************************************************************/ typedef void (*ActivationHandleFunc)(NMDevice *self); @@ -761,6 +763,9 @@ typedef struct _NMDevicePrivate { GVariant *ports_variant; /* Array of port devices D-Bus path */ char *prop_ip_iface; /* IP interface D-Bus property */ + + int autoconnect_retries; + gint32 autoconnect_retries_blocked_until; } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -778,7 +783,9 @@ static void _dev_l3_cfg_commit_type_reset(NMDevice *self); static gboolean nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure); static void nm_device_slave_notify_enslave(NMDevice *self, gboolean success); -static void nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason); +static void nm_device_slave_notify_release(NMDevice *self, + NMDeviceStateReason reason, + ReleaseSlaveType release_type); static void _dev_ipll6_start(NMDevice *self); @@ -6236,7 +6243,7 @@ nm_device_master_release_slave(NMDevice *self, release_type >= RELEASE_SLAVE_TYPE_CONFIG); /* raise notifications about the release, including clearing is_enslaved. */ - nm_device_slave_notify_release(slave, reason); + nm_device_slave_notify_release(slave, reason, release_type); /* keep both alive until the end of the function. * Transfers ownership from slave_priv->master. */ @@ -6536,12 +6543,16 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) g_return_if_fail(plink); - if (plink->master <= 0) - goto out; - - master = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, plink->master); - plink_master = nm_platform_link_get(nm_device_get_platform(self), plink->master); - plink_master_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink_master)); + if (plink->master > 0) { + master = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, plink->master); + plink_master = nm_platform_link_get(nm_device_get_platform(self), plink->master); + plink_master_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink_master)); + } else { + if (priv->master_ifindex == 0) + goto out; + master = NULL; + plink_master = NULL; + } if (master == NULL && plink_master && NM_IN_STRSET(plink_master->name, "ovs-system", "ovs-netdev") @@ -8024,7 +8035,9 @@ nm_device_slave_notify_enslave(NMDevice *self, gboolean success) * Notifies a slave that it has been released, and why. */ static void -nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) +nm_device_slave_notify_release(NMDevice *self, + NMDeviceStateReason reason, + ReleaseSlaveType release_type) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMConnection *connection = nm_device_get_applied_connection(self); @@ -8032,7 +8045,7 @@ nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) g_return_if_fail(priv->master); - if (!priv->is_enslaved) + if (!priv->is_enslaved && release_type == RELEASE_SLAVE_TYPE_NO_CONFIG) return; if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { @@ -8956,7 +8969,7 @@ nm_device_emit_recheck_assume(gpointer user_data) priv = NM_DEVICE_GET_PRIVATE(self); priv->recheck_assume_id = 0; - if (!nm_device_get_act_request(self)) + if (!priv->queued_act_request && !nm_device_get_act_request(self)) g_signal_emit(self, signals[RECHECK_ASSUME], 0); return G_SOURCE_REMOVE; @@ -9954,6 +9967,7 @@ nm_device_devip_set_state_full(NMDevice *self, nm_assert_addr_family_or_unspec(addr_family); nm_assert(NM_IN_SET(ip_state, + NM_DEVICE_IP_STATE_NONE, NM_DEVICE_IP_STATE_PENDING, NM_DEVICE_IP_STATE_READY, NM_DEVICE_IP_STATE_FAILED)); @@ -9961,7 +9975,7 @@ nm_device_devip_set_state_full(NMDevice *self, nm_assert((ip_state != NM_DEVICE_IP_STATE_FAILED) == (failed_reason == NM_DEVICE_STATE_REASON_NONE)); - nm_assert((ip_state != NM_DEVICE_IP_STATE_FAILED) || !l3cd); + nm_assert(NM_IN_SET(ip_state, NM_DEVICE_IP_STATE_PENDING, NM_DEVICE_IP_STATE_READY) || !l3cd); p = _dev_ipdev_data(self, addr_family); @@ -12206,7 +12220,7 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) } if (priv->ipshared_data_4.v4.firewall_config) { - nm_firewall_config_apply(priv->ipshared_data_4.v4.firewall_config, FALSE); + nm_firewall_config_apply_sync(priv->ipshared_data_4.v4.firewall_config, FALSE); nm_clear_pointer(&priv->ipshared_data_4.v4.firewall_config, nm_firewall_config_free); } @@ -12353,8 +12367,8 @@ _dev_ipshared4_start(NMDevice *self) goto out_fail; priv->ipshared_data_4.v4.firewall_config = - nm_firewall_config_new(ip_iface, ip4_addr.address, ip4_addr.plen); - nm_firewall_config_apply(priv->ipshared_data_4.v4.firewall_config, TRUE); + nm_firewall_config_new_shared(ip_iface, ip4_addr.address, ip4_addr.plen); + nm_firewall_config_apply_sync(priv->ipshared_data_4.v4.firewall_config, TRUE); priv->ipshared_data_4.v4.l3cd = nm_l3_config_data_ref(l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, l3cd, FALSE); @@ -16857,6 +16871,49 @@ nm_device_get_initial_hw_address(NMDevice *self) return NM_DEVICE_GET_PRIVATE(self)->hw_addr_initial; } +void +nm_device_set_autoconnect_retries(NMDevice *self, int tries) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->autoconnect_retries != tries) { + _LOGT(LOGD_DEVICE, "autoconnect: retries set %d", tries); + priv->autoconnect_retries = tries; + } + + if (tries) + priv->autoconnect_retries_blocked_until = 0; /* we are not blocked anymore */ + else + priv->autoconnect_retries_blocked_until = + nm_utils_get_monotonic_timestamp_sec() + AUTOCONNECT_RESET_RETRIES_TIMER; +} + +int +nm_device_get_autoconnect_retries(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + return priv->autoconnect_retries; +} + +gint32 +nm_device_autoconnect_retries_blocked_until(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + return priv->autoconnect_retries_blocked_until; +} + +void +nm_device_autoconnect_retries_reset(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + /* default value, we will sync. with connection value when needed */ + priv->autoconnect_retries = -2; + priv->autoconnect_retries_blocked_until = 0; +} + /** * nm_device_spec_match_list: * @self: an #NMDevice @@ -17161,6 +17218,13 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean /* If the device is not supposed to have addresses, * return an immediate empty result.*/ if (!nm_device_get_applied_connection(self)) { + nm_clear_pointer(&priv->hostname_resolver_x[IS_IPv4], _hostname_resolver_free); + NM_SET_OUT(out_wait, FALSE); + return NULL; + } + + if (!priv->carrier) { + nm_clear_pointer(&priv->hostname_resolver_x[IS_IPv4], _hostname_resolver_free); NM_SET_OUT(out_wait, FALSE); return NULL; } @@ -17601,6 +17665,8 @@ nm_device_init(NMDevice *self) priv->sys_iface_state_ = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; priv->promisc_reset = NM_OPTION_BOOL_DEFAULT; + + priv->autoconnect_retries = -2; } static GObject * diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index de850e68..fea46bb7 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -464,6 +464,11 @@ const char *nm_device_get_permanent_hw_address_full(NMDevice *self, gboolean *out_is_fake); const char *nm_device_get_initial_hw_address(NMDevice *dev); +void nm_device_set_autoconnect_retries(NMDevice *self, int tries); +int nm_device_get_autoconnect_retries(NMDevice *self); +gint32 nm_device_autoconnect_retries_blocked_until(NMDevice *self); +void nm_device_autoconnect_retries_reset(NMDevice *self); + NMDhcpConfig *nm_device_get_dhcp_config(NMDevice *dev, int addr_family); NML3Cfg *nm_device_get_l3cfg(NMDevice *self); diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index e7c96852..d3e858a1 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -18,6 +18,7 @@ #include "nm-manager.h" #include "nm-setting-ovs-external-ids.h" #include "nm-priv-helper-call.h" +#include "libnm-platform/nm-platform.h" /*****************************************************************************/ @@ -120,6 +121,7 @@ enum { static guint signals[LAST_SIGNAL] = {0}; typedef struct { + NMPlatform *platform; GSocketConnection *conn; GCancellable *conn_cancellable; char buf[4096]; /* Input buffer */ @@ -135,8 +137,14 @@ typedef struct { GHashTable *bridges; /* bridge uuid => OpenvswitchBridge */ char *db_uuid; guint num_failures; - guint num_pending_deletions; bool ready : 1; + struct { + GPtrArray *interfaces; /* Interface names we are waiting to go away */ + GSource *timeout_source; /* After all deletions complete, wait this + * timeout for interfaces to disappear */ + gulong link_changed_id; /* Platform link-changed signal handle */ + guint num_pending_del; /* Number of ovsdb deletions pending */ + } cleanup; } NMOvsdbPrivate; struct _NMOvsdb { @@ -161,6 +169,7 @@ static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposin static void ovsdb_read(NMOvsdb *self); static void ovsdb_write(NMOvsdb *self); static void ovsdb_next_command(NMOvsdb *self); +static void cleanup_check_ready(NMOvsdb *self); /*****************************************************************************/ @@ -2283,21 +2292,114 @@ ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing) } static void -_check_ready(NMOvsdb *self) +cleanup_emit_ready(NMOvsdb *self, const char *reason) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); + + _LOGT("cleanup: ready (%s)", reason); + + nm_clear_pointer(&priv->cleanup.interfaces, g_ptr_array_unref); + nm_clear_g_source_inst(&priv->cleanup.timeout_source); + nm_clear_g_signal_handler(priv->platform, &priv->cleanup.link_changed_id); + + priv->ready = TRUE; + g_signal_emit(self, signals[READY], 0); + nm_manager_unblock_failed_ovs_interfaces(nm_manager_get()); +} + +static gboolean +cleanup_timeout(NMOvsdb *self) +{ + cleanup_emit_ready(self, "timeout"); + return G_SOURCE_CONTINUE; +} + +static void +cleanup_link_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + NMPlatformLink *plink, + int change_type_i, + gpointer user_data) +{ + const NMPlatformSignalChangeType change_type = change_type_i; + + if (change_type != NM_PLATFORM_SIGNAL_REMOVED) + return; + + cleanup_check_ready(user_data); +} + +static void +cleanup_check_ready(NMOvsdb *self) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); + guint i = 0; nm_assert(!priv->ready); - if (priv->num_pending_deletions == 0) { - priv->ready = TRUE; - g_signal_emit(self, signals[READY], 0); - nm_manager_unblock_failed_ovs_interfaces(nm_manager_get()); + if (priv->cleanup.num_pending_del > 0) + return; + + /* After we have deleted an interface from ovsdb, the link will stay + * in platform until ovs-vswitch removes it. To avoid race conditions, + * we need to wait until the link goes away; otherwise, after adding the + * interface again, these race conditions can happen: + * 1) we see the link in platform, and proceed with activation. But after + * that, ovs-vswitchd reads the updates from ovsdb-server and deletes/recreates + * the link. + * 2) ovs-vswitch combines the delete/insert of the interface to a no-op. NM sees + * the link staying in platform, but doesn't know whether the link is ready + * or we are again in case 1) + * In other words, it's necessary to wait that the link goes away before inserting + * the interface again. + */ + while (i < nm_g_ptr_array_len(priv->cleanup.interfaces)) { + const char *ifname; + const NMDedupMultiHeadEntry *pl_links_head_entry; + NMDedupMultiIter pliter; + const NMPlatformLink *link; + gboolean found = FALSE; + + ifname = priv->cleanup.interfaces->pdata[i]; + pl_links_head_entry = nm_platform_lookup_link_by_ifname(priv->platform, ifname); + nmp_cache_iter_for_each_link (&pliter, pl_links_head_entry, &link) { + if (link->type == NM_LINK_TYPE_OPENVSWITCH + && nmp_object_is_visible(NMP_OBJECT_UP_CAST(link))) { + found = TRUE; + break; + } + } + + if (!found) { + g_ptr_array_remove_index_fast(priv->cleanup.interfaces, i); + continue; + } + i++; } + + if (nm_g_ptr_array_len(priv->cleanup.interfaces) == 0) { + cleanup_emit_ready(self, "all interfaces deleted"); + return; + } + + _LOGT("cleanup: still waiting for %d interfaces", priv->cleanup.interfaces->len); + + if (priv->cleanup.timeout_source) { + /* We already registered the timeout/change-callback */ + return; + } + + priv->cleanup.timeout_source = + nm_g_timeout_add_seconds_source(6, G_SOURCE_FUNC(cleanup_timeout), self); + priv->cleanup.link_changed_id = g_signal_connect(priv->platform, + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK(cleanup_link_cb), + self); } static void -_del_initial_iface_cb(GError *error, gpointer user_data) +cleanup_del_iface_cb(GError *error, gpointer user_data) { NMOvsdb *self; gs_free char *ifname = NULL; @@ -2309,18 +2411,18 @@ _del_initial_iface_cb(GError *error, gpointer user_data) return; priv = NM_OVSDB_GET_PRIVATE(self); - nm_assert(priv->num_pending_deletions > 0); - priv->num_pending_deletions--; + nm_assert(priv->cleanup.num_pending_del > 0); + priv->cleanup.num_pending_del--; - _LOGD("delete initial interface '%s': %s %s%s%s, pending %u", + _LOGD("cleanup: deleted interface '%s': %s %s%s%s, pending %u", ifname, error ? "error" : "success", error ? "(" : "", error ? error->message : "", error ? ")" : "", - priv->num_pending_deletions); + priv->cleanup.num_pending_del); - _check_ready(self); + cleanup_check_ready(self); } static void @@ -2331,7 +2433,7 @@ ovsdb_cleanup_initial_interfaces(NMOvsdb *self) NMUtilsUserData *data; GHashTableIter iter; - if (priv->ready || priv->num_pending_deletions != 0) + if (priv->ready || priv->cleanup.num_pending_del > 0 || priv->cleanup.interfaces) return; /* Delete OVS interfaces added by NM. Bridges and ports and @@ -2339,17 +2441,22 @@ ovsdb_cleanup_initial_interfaces(NMOvsdb *self) * when no interface is present. */ g_hash_table_iter_init(&iter, self->_priv.interfaces); while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &interface)) { - if (interface->connection_uuid) { - priv->num_pending_deletions++; - _LOGD("deleting initial interface '%s' (pending: %u)", - interface->name, - priv->num_pending_deletions); - data = nm_utils_user_data_pack(self, g_strdup(interface->name)); - nm_ovsdb_del_interface(self, interface->name, _del_initial_iface_cb, data); + if (!interface->connection_uuid) { + /* not created by NM, ignore */ + continue; } + + if (!priv->cleanup.interfaces) + priv->cleanup.interfaces = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(priv->cleanup.interfaces, g_strdup(interface->name)); + + _LOGD("cleanup: deleting interface '%s'", interface->name); + priv->cleanup.num_pending_del++; + data = nm_utils_user_data_pack(self, g_strdup(interface->name)); + nm_ovsdb_del_interface(self, interface->name, cleanup_del_iface_cb, data); } - _check_ready(self); + cleanup_check_ready(self); } static void @@ -2622,8 +2729,9 @@ nm_ovsdb_init(NMOvsdb *self) c_list_init(&priv->calls_lst_head); - priv->input = g_string_new(NULL); - priv->output = g_string_new(NULL); + priv->platform = g_object_ref(NM_PLATFORM_GET); + priv->input = g_string_new(NULL); + priv->output = g_string_new(NULL); priv->bridges = g_hash_table_new_full(nm_pstr_hash, nm_pstr_equal, (GDestroyNotify) _free_bridge, NULL); priv->ports = @@ -2653,6 +2761,7 @@ dispose(GObject *object) priv->output = NULL; } + g_clear_object(&priv->platform); nm_clear_pointer(&priv->bridges, g_hash_table_destroy); nm_clear_pointer(&priv->ports, g_hash_table_destroy); nm_clear_pointer(&priv->interfaces, g_hash_table_destroy); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 77cfeecf..1329b953 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -115,9 +115,6 @@ typedef struct _NMDhcpClientPrivate { in_addr_t addr; NMOptionBool state; } acd; - struct { - GDBusMethodInvocation *invocation; - } bound; } v4; struct { GSource *lladdr_timeout_source; @@ -125,6 +122,8 @@ typedef struct _NMDhcpClientPrivate { } v6; }; + GDBusMethodInvocation *invocation; + struct { gulong id; bool wait_dhcp_commit : 1; @@ -909,13 +908,10 @@ _accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - if (!NM_IS_IPv4(priv->config.addr_family)) + if (!priv->invocation) return TRUE; - if (!priv->v4.bound.invocation) - return TRUE; - - g_dbus_method_invocation_return_value(g_steal_pointer(&priv->v4.bound.invocation), NULL); + g_dbus_method_invocation_return_value(g_steal_pointer(&priv->invocation), NULL); return TRUE; } @@ -939,20 +935,17 @@ decline(NMDhcpClient *self, const NML3ConfigData *l3cd, const char *error_messag { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - if (!NM_IS_IPv4(priv->config.addr_family)) - return TRUE; - - if (!priv->v4.bound.invocation) { + if (!priv->invocation) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling decline in unexpected script state"); return FALSE; } - - g_dbus_method_invocation_return_error(g_steal_pointer(&priv->v4.bound.invocation), + g_dbus_method_invocation_return_error(g_steal_pointer(&priv->invocation), NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "acd failed"); + NM_IS_IPv4(priv->config.addr_family) ? "ACD failed" + : "DAD failed"); return TRUE; } @@ -1043,8 +1036,11 @@ ipv6_lladdr_find(NMDhcpClient *self) return NULL; } -static const NMPlatformIP6Address * -ipv6_tentative_addr_find(NMDhcpClient *self) +static void +ipv6_tentative_addr_check(NMDhcpClient *self, + GPtrArray **tentative, + GPtrArray **missing, + const NMPlatformIP6Address **valid) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); NMDedupMultiIter iter; @@ -1062,16 +1058,26 @@ ipv6_tentative_addr_find(NMDhcpClient *self) NMP_CACHE_ID_TYPE_OBJECT_TYPE, &needle)); if (!pladdr) { - /* Address was removed from platform */ + /* address removed: we assume that's because DAD failed */ + if (missing) { + if (!*missing) + *missing = g_ptr_array_new(); + g_ptr_array_add(*missing, (gpointer) addr); + } continue; } if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) - return pladdr; - } + && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + if (tentative) { + if (!*tentative) + *tentative = g_ptr_array_new(); + g_ptr_array_add(*tentative, (gpointer) addr); + } + } - return NULL; + NM_SET_OUT(valid, addr); + } } static void @@ -1108,21 +1114,61 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE && priv->l3cfg_notify.wait_ipv6_dad) { - const NMPlatformIP6Address *tentative; + gs_unref_ptrarray GPtrArray *tentative = NULL; + gs_unref_ptrarray GPtrArray *missing = NULL; + const NMPlatformIP6Address *valid = NULL; + char str[NM_UTILS_TO_STRING_BUFFER_SIZE]; + guint i; + gs_free_error GError *error = NULL; + + ipv6_tentative_addr_check(self, &tentative, &missing, &valid); + if (tentative) { + for (i = 0; i < tentative->len; i++) { + _LOGD("still waiting DAD for address: %s", + nm_platform_ip6_address_to_string(tentative->pdata[i], str, sizeof(str))); + } + } else { + /* done */ - tentative = ipv6_tentative_addr_find(self); - if (!tentative) { - _LOGD("addresses in the lease completed DAD"); priv->l3cfg_notify.wait_ipv6_dad = FALSE; nm_clear_g_source_inst(&priv->v6.dad_timeout_source); l3_cfg_notify_check_connected(self); - _emit_notify( - self, - &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = { - .l3cd = priv->l3cd_curr, - .accepted = TRUE, - }})); + + if (missing) { + for (i = 0; i < missing->len; i++) { + _LOGE("DAD failed for address: %s", + nm_platform_ip6_address_to_string(missing->pdata[i], str, sizeof(str))); + } + } + + if (valid) { + /* at least one non-duplicate address */ + _LOGD("addresses in the lease completed DAD: accept the lease"); + + if (_dhcp_client_accept(self, priv->l3cd_curr, &error)) { + _emit_notify(self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = TRUE, + }})); + } else { + gs_free char *reason = + g_strdup_printf("error accepting lease: %s", error->message); + + _LOGD("accept failed: %s", error->message); + _emit_notify(self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = reason, + })); + } + } else { + _LOGD("decline the lease"); + if (!_dhcp_client_decline(self, priv->l3cd_curr, "DAD failed", &error)) + _LOGD("decline failed: %s", error->message); + } } } @@ -1155,20 +1201,23 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp address4->peer_address)) goto wait_dhcp_commit_done; } else { - const NMPlatformIP6Address *address6 = (const NMPlatformIP6Address *) lease_address; - const NMPlatformIP6Address *tentative; - char str[NM_UTILS_TO_STRING_BUFFER_SIZE]; + const NMPlatformIP6Address *address6 = (const NMPlatformIP6Address *) lease_address; + gs_unref_ptrarray GPtrArray *tentative = NULL; + char str[NM_UTILS_TO_STRING_BUFFER_SIZE]; + guint i; if (!nm_l3_config_data_lookup_address_6(committed_l3cd, &address6->address)) goto wait_dhcp_commit_done; - tentative = ipv6_tentative_addr_find(self); + ipv6_tentative_addr_check(self, &tentative, NULL, NULL); if (tentative) { priv->l3cfg_notify.wait_ipv6_dad = TRUE; priv->v6.dad_timeout_source = nm_g_timeout_add_seconds_source(30, ipv6_dad_timeout, self); - _LOGD("wait DAD for address %s", - nm_platform_ip6_address_to_string(tentative, str, sizeof(str))); + for (i = 0; i < tentative->len; i++) { + _LOGD("wait DAD for address %s", + nm_platform_ip6_address_to_string(tentative->pdata[i], str, sizeof(str))); + } } else { priv->l3cfg_notify.wait_ipv6_dad = FALSE; nm_clear_g_source_inst(&priv->v6.dad_timeout_source); @@ -1179,22 +1228,22 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp l3_cfg_notify_check_connected(self); - _LOGD("accept lease"); + if (priv->config.addr_family == AF_INET || !priv->l3cfg_notify.wait_ipv6_dad) { + _LOGD("accept lease"); - if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) { - gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message); + if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) { + gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message); - _LOGD("accept failed: %s", error->message); + _LOGD("accept failed: %s", error->message); - _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = reason, - })); - goto wait_dhcp_commit_done; - } + _emit_notify(self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = reason, + })); + goto wait_dhcp_commit_done; + } - if (priv->config.addr_family == AF_INET || !priv->l3cfg_notify.wait_ipv6_dad) { _emit_notify( self, &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, @@ -1368,8 +1417,8 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) priv->is_stopped = TRUE; - if (NM_IS_IPv4(priv->config.addr_family) && priv->v4.bound.invocation) { - g_dbus_method_invocation_return_error(g_steal_pointer(&priv->v4.bound.invocation), + if (priv->invocation) { + g_dbus_method_invocation_return_error(g_steal_pointer(&priv->invocation), NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "dhcp stopping"); @@ -1528,7 +1577,6 @@ nm_dhcp_client_handle_event(gpointer unused, NMPlatformIP6Address prefix = { 0, }; - int IS_IPv4; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); g_return_val_if_fail(iface != NULL, FALSE); @@ -1625,16 +1673,13 @@ nm_dhcp_client_handle_event(gpointer unused, client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_FAIL; } - IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); - - if (IS_IPv4 && priv->v4.bound.invocation) - g_dbus_method_invocation_return_value(g_steal_pointer(&priv->v4.bound.invocation), NULL); + if (priv->invocation) + g_dbus_method_invocation_return_value(g_steal_pointer(&priv->invocation), NULL); - if (IS_IPv4 - && NM_IN_SET(client_event_type, - NM_DHCP_CLIENT_EVENT_TYPE_BOUND, - NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)) - priv->v4.bound.invocation = g_steal_pointer(&invocation); + if (NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)) + priv->invocation = g_steal_pointer(&invocation); _nm_dhcp_client_notify(self, client_event_type, l3cd); @@ -1785,10 +1830,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps * explicitly initialize the respective union member. */ if (NM_IS_IPv4(priv->config.addr_family)) { priv->v4 = (typeof(priv->v4)){ - .bound = - { - .invocation = NULL, - }, .acd = { .addr = INADDR_ANY, diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c index 5a17f4e8..78db617c 100644 --- a/src/core/dhcp/nm-dhcp-helper.c +++ b/src/core/dhcp/nm-dhcp-helper.c @@ -114,6 +114,8 @@ main(int argc, char *argv[]) gint64 time_start; gint64 time_end; gint64 remaining_time; + gboolean IS_IPv4; + const char *reason; /* Connecting to the unix socket can fail with EAGAIN if there are too * many pending connections and the server can't accept them in time @@ -124,7 +126,19 @@ main(int argc, char *argv[]) time_end = time_start + (5000 * 1000L); try_count = 0; - _LOGi("nm-dhcp-helper: event called"); + reason = getenv("reason"); + + _LOGi("nm-dhcp-helper: event called: %s", reason); + + IS_IPv4 = !NM_IN_STRSET(reason, + "PREINIT6", + "BOUND6", + "RENEW6", + "REBIND6", + "DEPREF6", + "EXPIRE6", + "RELEASE6", + "STOP6"); do_connect: try_count++; @@ -244,5 +258,6 @@ out: } _LOGi("success: %s", success ? "YES" : "NO"); - return success ? EXIT_SUCCESS : EXIT_FAILURE; + /* The error code to send a decline depends on the address family */ + return success ? EXIT_SUCCESS : (IS_IPv4 ? 1 : 3); } diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 1e54452a..a2fead3f 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -2039,8 +2039,15 @@ nm_dns_manager_set_ip_config(NMDnsManager *self, if (!ip_data) { ip_data = _dns_config_ip_data_new(data, addr_family, source_tag, l3cd, ip_config_type); - if (!any_removed) + priv->ip_data_lst_need_sort = TRUE; + if (!any_removed) { + /* `any_removed` tracks whether we deleted any ip_data. If that happened, + * we already compared the old and new l3cds and set `changed` accordingly. + * Here we only need to set `changed` if we are adding a new ip_data without + * removing the old one. + */ changed = TRUE; + } } else { ip_data->ip_config_type = ip_config_type; changed = TRUE; diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index 0f512e38..753e3fb5 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -585,7 +585,7 @@ _merge_keyfiles(GKeyFile *keyfile_user, GKeyFile *keyfile_intern) if (!keys) continue; - is_intern = g_str_has_prefix(group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + is_intern = NM_STR_HAS_PREFIX(group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); if (!is_intern && g_key_file_has_key(keyfile_intern, group, @@ -634,9 +634,11 @@ _nm_config_data_log_sort(const char **pa, const char **pb, gpointer dummy) const char *a = *pa; const char *b = *pb; + nm_assert(a && b && !nm_streq(a, b)); + /* we sort intern groups to the end. */ - a_is_intern = g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); - b_is_intern = g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + a_is_intern = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + b_is_intern = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); if (a_is_intern && b_is_intern) return 0; @@ -646,8 +648,8 @@ _nm_config_data_log_sort(const char **pa, const char **pb, gpointer dummy) return -1; /* we sort connection groups before intern groups (to the end). */ - a_is_connection = a && g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); - b_is_connection = b && g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); + a_is_connection = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); + b_is_connection = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); if (a_is_connection && b_is_connection) { /* if both are connection groups, we want the explicit [connection] group first. */ @@ -668,8 +670,8 @@ _nm_config_data_log_sort(const char **pa, const char **pb, gpointer dummy) return -1; /* we sort device groups before connection groups (to the end). */ - a_is_device = a && g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); - b_is_device = b && g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); + a_is_device = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); + b_is_device = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE); if (a_is_device && b_is_device) { /* if both are device groups, we want the explicit [device] group first. */ @@ -770,27 +772,48 @@ nm_config_data_log(const NMConfigData *self, groups_full = g_ptr_array_sized_new(ngroups + 5); if (ngroups) { + /* g_key_file_get_groups() can return duplicates ( :( ), but the + * keyfile that we constructed should not have any. Assert for that. */ + nm_assert(!nm_strv_has_duplicate((const char *const *) groups, ngroups, FALSE)); + g_ptr_array_set_size(groups_full, ngroups); memcpy(groups_full->pdata, groups, sizeof(groups[0]) * ngroups); - g_ptr_array_sort_with_data(groups_full, (GCompareDataFunc) _nm_config_data_log_sort, NULL); } if (print_default) { for (g = 0; g < G_N_ELEMENTS(default_values); g++) { const char *group = default_values[g].group; - gssize idx; + guint g2; - idx = nm_utils_array_find_binary_search((gconstpointer *) groups_full->pdata, - sizeof(char *), - groups_full->len, - &group, - (GCompareDataFunc) _nm_config_data_log_sort, - NULL); - if (idx < 0) - g_ptr_array_insert(groups_full, (~idx), (gpointer) group); + if (g > 0) { + if (nm_streq(group, default_values[g - 1].group)) { + /* Repeated values. We already added this one. Skip */ + continue; + } + if (NM_MORE_ASSERT_ONCE(20)) { + /* We require that the default values are grouped by their "group". + * That is, all default values for a certain "group" are close to + * each other in the list. Assert for that. */ + for (g2 = g + 1; g2 < groups_full->len; g2++) { + nm_assert(!nm_streq(default_values[g - 1].group, default_values[g2].group)); + } + } + } + + for (g2 = 0; g2 < groups_full->len; g2++) { + if (nm_streq(group, groups_full->pdata[g2])) + goto next; + } + + g_ptr_array_add(groups_full, (gpointer) group); + +next: + (void) 0; } } + g_ptr_array_sort_with_data(groups_full, (GCompareDataFunc) _nm_config_data_log_sort, NULL); + if (!stream) _LOG(stream, prefix, "config-data[%p]: %u groups", self, groups_full->len); diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 1311f503..e482ab96 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -111,6 +111,8 @@ _share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const c return nm_str_buf_finalize(&strbuf, NULL); } +/*****************************************************************************/ + static gboolean _share_iptables_call_v(const char *const *argv) { @@ -171,7 +173,7 @@ _share_iptables_chain_add(const char *table, const char *chain) } static void -_share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) +_share_iptables_set_masquerade_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen) { char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; gs_free char *comment_name = NULL; @@ -182,7 +184,7 @@ _share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t add _share_iptables_call("" IPTABLES_PATH "", "--table", "nat", - add ? "--insert" : "--delete", + up ? "--insert" : "--delete", "POSTROUTING", "--source", str_subnet, @@ -309,8 +311,8 @@ _share_iptables_set_shared_chains_delete(const char *chain_input, const char *ch _share_iptables_chain_delete("filter", chain_forward); } -_nm_unused static void -_share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, guint plen) +static void +_share_iptables_set_shared_sync(gboolean up, const char *ip_iface, in_addr_t addr, guint plen) { gs_free char *comment_name = NULL; gs_free char *chain_input = NULL; @@ -320,13 +322,13 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g chain_input = _share_iptables_get_name(TRUE, "nm-sh-in", ip_iface); chain_forward = _share_iptables_get_name(TRUE, "nm-sh-fw", ip_iface); - if (add) + if (up) _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); _share_iptables_call("" IPTABLES_PATH "", "--table", "filter", - add ? "--insert" : "--delete", + up ? "--insert" : "--delete", "INPUT", "--in-interface", ip_iface, @@ -340,7 +342,7 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g _share_iptables_call("" IPTABLES_PATH "", "--table", "filter", - add ? "--insert" : "--delete", + up ? "--insert" : "--delete", "FORWARD", "--jump", chain_forward, @@ -349,7 +351,7 @@ _share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, g "--comment", comment_name); - if (!add) + if (!up) _share_iptables_set_shared_chains_delete(chain_input, chain_forward); } @@ -428,14 +430,21 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user } else if (g_subprocess_get_successful(call_data->subprocess)) { nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: command successful", call_data->identifier); } else { + char buf[NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN]; gs_free char *ss_stdout = NULL; gs_free char *ss_stderr = NULL; gboolean print_stdout = (stdout_buf && g_bytes_get_size(stdout_buf) > 0); gboolean print_stderr = (stderr_buf && g_bytes_get_size(stderr_buf) > 0); + int status; + + status = g_subprocess_get_status(call_data->subprocess); + + nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf)); nm_log_warn(LOGD_SHARING, - "firewall: nft[%s]: command failed:%s%s%s%s%s%s%s", + "firewall: nft[%s]: command %s:%s%s%s%s%s%s%s", call_data->identifier, + buf, print_stdout || print_stderr ? "" : " unknown reason", NM_PRINT_FMT_QUOTED( print_stdout, @@ -453,6 +462,8 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user &ss_stderr), "\")", "")); + + nm_utils_error_set(&error, NM_UTILS_ERROR_COMMAND_FAILED, "nft command %s", buf); } _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); @@ -486,23 +497,31 @@ _fw_nft_call_timeout_cb(gpointer user_data) return G_SOURCE_CONTINUE; } -static void -_fw_nft_call(GBytes *stdin_buf, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer callback_user_data) +void +nm_firewall_nft_call(GBytes *stdin_buf, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_user_data) { gs_unref_object GSubprocessLauncher *subprocess_launcher = NULL; gs_free_error GError *error = NULL; FwNftCallData *call_data; + gs_free char *ss1 = NULL; call_data = g_slice_new(FwNftCallData); *call_data = (FwNftCallData){ - .task = nm_g_task_new(NULL, cancellable, _fw_nft_call, callback, callback_user_data), - .subprocess = NULL, + .task = + nm_g_task_new(NULL, cancellable, nm_firewall_nft_call, callback, callback_user_data), + .subprocess = NULL, .timeout_source = NULL, }; + nm_log_trace(LOGD_SHARING, + "firewall: nft: call command: [ '%s' ]", + nm_utils_buf_utf8safe_escape_bytes(stdin_buf, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &ss1)); + if (cancellable) { call_data->cancellable_id = g_cancellable_connect(cancellable, G_CALLBACK(_fw_nft_call_cancelled_cb), @@ -554,10 +573,10 @@ _fw_nft_call(GBytes *stdin_buf, g_task_get_context(call_data->task)); } -static gboolean -_fw_nft_call_finish(GAsyncResult *result, GError **error) +gboolean +nm_firewall_nft_call_finish(GAsyncResult *result, GError **error) { - g_return_val_if_fail(nm_g_task_is_valid(result, NULL, _fw_nft_call), FALSE); + g_return_val_if_fail(nm_g_task_is_valid(result, NULL, nm_firewall_nft_call), FALSE); return g_task_propagate_boolean(G_TASK(result), error); } @@ -575,7 +594,7 @@ _fw_nft_call_sync_done(GObject *source, GAsyncResult *result, gpointer user_data { FwNftCallSyncData *data = user_data; - data->success = _fw_nft_call_finish(result, data->error); + data->success = nm_firewall_nft_call_finish(result, data->error); g_main_loop_quit(data->loop); } @@ -590,7 +609,7 @@ _fw_nft_call_sync(GBytes *stdin_buf, GError **error) .error = error, }; - _fw_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data); + nm_firewall_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data); g_main_loop_run(main_loop); return data.success; @@ -598,25 +617,30 @@ _fw_nft_call_sync(GBytes *stdin_buf, GError **error) /*****************************************************************************/ +#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__) + static void -_fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) +_fw_nft_append_cmd_table(NMStrBuf *strbuf, const char *family, const char *table_name, gboolean up) +{ + /* Either delete the table, or create/flush it. */ + _append(strbuf, "add table %s %s", family, table_name); + _append(strbuf, "%s table %s %s", up ? "flush" : "delete", family, table_name); +} + +static GBytes * +_fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, guint8 plen) { nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); - gs_unref_bytes GBytes *stdin_buf = NULL; gs_free char *table_name = NULL; - gs_free char *ss1 = NULL; char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); _share_iptables_subnet_to_str(str_subnet, addr, plen); -#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__) - - _append(&strbuf, "add table ip %s", table_name); - _append(&strbuf, "%s table ip %s", add ? "flush" : "delete", table_name); + _fw_nft_append_cmd_table(&strbuf, "ip", table_name, up); - if (add) { + if (up) { _append(&strbuf, "add chain ip %s nat_postrouting {" " type nat hook postrouting priority 100; policy accept; " @@ -631,16 +655,15 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) /* This filter_input chain serves no real purpose, because "accept" only stops * evaluation of the current rule. It cannot fully accept the packet. Since * this chain has no other rules, it is useless in this form. + * + * _append(&strbuf, + * "add chain ip %s filter_input {" + * " type filter hook input priority 0; policy accept; " + * "};", + * table_name); + * _append(&strbuf, "add rule ip %s filter_input tcp dport { 67, 53 } accept;", table_name); + * _append(&strbuf, "add rule ip %s filter_input udp dport { 67, 53 } accept;", table_name); */ - /* - _append(&strbuf, - "add chain ip %s filter_input {" - " type filter hook input priority 0; policy accept; " - "};", - table_name); - _append(&strbuf, "add rule ip %s filter_input tcp dport { 67, 53 } accept;", table_name); - _append(&strbuf, "add rule ip %s filter_input udp dport { 67, 53 } accept;", table_name); - */ _append(&strbuf, "add chain ip %s filter_forward {" @@ -673,14 +696,7 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) ip_iface); } - nm_log_trace(LOGD_SHARING, - "firewall: nft command: [ %s ]", - nm_utils_str_utf8safe_escape(nm_str_buf_get_str(&strbuf), - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, - &ss1)); - - stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf); - _fw_nft_call_sync(stdin_buf, NULL); + return nm_str_buf_finalize_to_gbytes(&strbuf); } /*****************************************************************************/ @@ -692,7 +708,7 @@ struct _NMFirewallConfig { }; NMFirewallConfig * -nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen) +nm_firewall_config_new_shared(const char *ip_iface, in_addr_t addr, guint8 plen) { NMFirewallConfig *self; @@ -719,17 +735,24 @@ nm_firewall_config_free(NMFirewallConfig *self) nm_g_slice_free(self); } +/*****************************************************************************/ + void -nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared) +nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up) { switch (nm_firewall_utils_get_backend()) { case NM_FIREWALL_BACKEND_IPTABLES: - _share_iptables_set_masquerade(shared, self->ip_iface, self->addr, self->plen); - _share_iptables_set_shared(shared, self->ip_iface, self->addr, self->plen); + _share_iptables_set_masquerade_sync(up, self->ip_iface, self->addr, self->plen); + _share_iptables_set_shared_sync(up, self->ip_iface, self->addr, self->plen); break; case NM_FIREWALL_BACKEND_NFTABLES: - _fw_nft_set(shared, self->ip_iface, self->addr, self->plen); + { + gs_unref_bytes GBytes *stdin_buf = NULL; + + stdin_buf = _fw_nft_set_shared_construct(up, self->ip_iface, self->addr, self->plen); + _fw_nft_call_sync(stdin_buf, NULL); break; + } case NM_FIREWALL_BACKEND_NONE: break; default: diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h index 3d6c8a69..9d883fea 100644 --- a/src/core/nm-firewall-utils.h +++ b/src/core/nm-firewall-utils.h @@ -20,10 +20,19 @@ NMFirewallBackend nm_firewall_utils_get_backend(void); typedef struct _NMFirewallConfig NMFirewallConfig; -NMFirewallConfig *nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen); +NMFirewallConfig *nm_firewall_config_new_shared(const char *ip_iface, in_addr_t addr, guint8 plen); void nm_firewall_config_free(NMFirewallConfig *self); -void nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared); +void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up); + +/*****************************************************************************/ + +void nm_firewall_nft_call(GBytes *stdin_buf, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_user_data); + +gboolean nm_firewall_nft_call_finish(GAsyncResult *result, GError **error); #endif /* __NM_FIREWALL_UTILS_H__ */ diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 16b0211f..518fc596 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -797,6 +797,20 @@ device_dns_lookup_done(NMDevice *device, gpointer user_data) } static void +device_carrier_changed(NMDevice *device, GParamSpec *pspec, gpointer user_data) +{ + NMPolicyPrivate *priv = user_data; + NMPolicy *self = _PRIV_TO_SELF(priv); + gs_free char *msg = NULL; + + if (nm_device_has_carrier(device)) { + g_signal_handlers_disconnect_by_func(device, device_carrier_changed, priv); + msg = g_strdup_printf("device '%s' got carrier", nm_device_get_iface(device)); + update_system_hostname(self, msg); + } +} + +static void update_system_hostname(NMPolicy *self, const char *msg) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); @@ -880,6 +894,7 @@ update_system_hostname(NMPolicy *self, const char *msg) info = &g_array_index(infos, DeviceHostnameInfo, i); addr_family = info->IS_IPv4 ? AF_INET : AF_INET6; g_signal_handlers_disconnect_by_func(info->device, device_dns_lookup_done, self); + g_signal_handlers_disconnect_by_func(info->device, device_carrier_changed, priv); if (info->from_dhcp) { dhcp_config = nm_device_get_dhcp_config(info->device, addr_family); @@ -905,10 +920,18 @@ update_system_hostname(NMPolicy *self, const char *msg) if (priv->hostname_mode != NM_POLICY_HOSTNAME_MODE_DHCP) { if (info->from_dns) { - const char *result; - gboolean wait = FALSE; + const char *result = NULL; + gboolean wait = FALSE; - result = nm_device_get_hostname_from_dns_lookup(info->device, addr_family, &wait); + if (nm_device_has_carrier(info->device)) { + result = + nm_device_get_hostname_from_dns_lookup(info->device, addr_family, &wait); + } else { + g_signal_connect(info->device, + "notify::" NM_DEVICE_CARRIER, + G_CALLBACK(device_carrier_changed), + priv); + } if (result) { _set_hostname(self, result, "from address lookup"); return; @@ -1556,6 +1579,7 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); NMSettingsConnection *const *connections = NULL; guint i; + gboolean multiconnect = FALSE; _LOGT(LOGD_DEVICE, "unblocking failed OVS interfaces"); @@ -1563,6 +1587,13 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) for (i = 0; connections[i]; i++) { NMSettingsConnection *sett_conn = connections[i]; NMConnection *connection = nm_settings_connection_get_connection(sett_conn); + NMSettingConnection *s_con = nm_connection_get_setting_connection(connection); + + /* Check if any connection is connect multiple */ + if (s_con + && nm_setting_connection_get_multi_connect(s_con) + == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) + multiconnect = TRUE; if (nm_connection_get_setting_ovs_interface(connection)) { nm_settings_connection_autoconnect_retries_reset(sett_conn); @@ -1572,6 +1603,18 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) FALSE); } } + + /* There is, at least, one multiconnect connection with an OVS setting. + * Let's check the OVS devices retries */ + if (multiconnect) { + NMDevice *device; + GHashTableIter h_iter; + g_hash_table_iter_init(&h_iter, priv->devices); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { + if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) + nm_device_autoconnect_retries_reset(device); + } + } } static gboolean @@ -1583,7 +1626,8 @@ reset_autoconnect_all( NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); NMSettingsConnection *const *connections = NULL; guint i; - gboolean changed = FALSE; + gboolean changed = FALSE; + gboolean multiconnect = FALSE; _LOGD(LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s", @@ -1594,6 +1638,8 @@ reset_autoconnect_all( connections = nm_settings_get_connections(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *sett_conn = connections[i]; + NMSettingConnection *s_con = + nm_connection_get_setting_connection(nm_settings_connection_get_connection(sett_conn)); if (device && !nm_device_check_connection_compatible( @@ -1602,6 +1648,11 @@ reset_autoconnect_all( NULL)) continue; + if (s_con + && nm_setting_connection_get_multi_connect(s_con) + == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) + multiconnect = TRUE; + if (only_no_secrets) { /* we only reset the no-secrets blocked flag. */ if (nm_settings_connection_autoconnect_blocked_reason_set( @@ -1630,6 +1681,20 @@ reset_autoconnect_all( } } } + + /* There is, at least, one multiconnect connection. Let's check the devices retries */ + if (multiconnect) { + NMDevice *device_iter; + GHashTableIter h_iter; + g_hash_table_iter_init(&h_iter, priv->devices); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &device_iter, NULL)) { + if (nm_device_get_autoconnect_retries(device_iter) != -2) { + nm_device_autoconnect_retries_reset(device_iter); + changed = TRUE; + } + } + } + return changed; } @@ -1687,7 +1752,8 @@ reset_connections_retries(gpointer user_data) NMSettingsConnection *const *connections = NULL; guint i; gint32 con_stamp, min_stamp, now; - gboolean changed = FALSE; + gboolean changed = FALSE; + gboolean multiconnect = FALSE; priv->reset_retries_id = 0; @@ -1696,6 +1762,14 @@ reset_connections_retries(gpointer user_data) connections = nm_settings_get_connections(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; + NMSettingConnection *s_con = + nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection)); + + /* Check if any connection is connect multiple */ + if (s_con + && nm_setting_connection_get_multi_connect(s_con) + == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) + multiconnect = TRUE; con_stamp = nm_settings_connection_autoconnect_retries_blocked_until(connection); if (con_stamp == 0) @@ -1708,6 +1782,25 @@ reset_connections_retries(gpointer user_data) min_stamp = con_stamp; } + /* There is, at least, one multiconnect connection. Let's check the devices retries */ + if (multiconnect) { + NMDevice *device; + GHashTableIter h_iter; + g_hash_table_iter_init(&h_iter, priv->devices); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { + con_stamp = nm_device_autoconnect_retries_blocked_until(device); + + /* default value in device is -2, which means, we do not care */ + if (con_stamp <= 0) + continue; + if (con_stamp <= now) { + nm_device_autoconnect_retries_reset(device); + changed = TRUE; + } else if (min_stamp == 0 || min_stamp > con_stamp) + min_stamp = con_stamp; + } + } + /* Schedule the handler again if there are some stamps left */ if (min_stamp != 0) priv->reset_retries_id = @@ -1721,21 +1814,31 @@ reset_connections_retries(gpointer user_data) } static void -_connection_autoconnect_retries_set(NMPolicy *self, NMSettingsConnection *connection, int tries) +_connection_autoconnect_retries_set(NMPolicy *self, + NMSettingsConnection *connection, + NMDevice *device, + int tries) { - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); + NMSettingConnection *s_con; + gint32 retry_time; nm_assert(NM_IS_SETTINGS_CONNECTION(connection)); nm_assert(tries >= 0); - nm_settings_connection_autoconnect_retries_set(connection, tries); + s_con = nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection)); + if (s_con + && nm_setting_connection_get_multi_connect(s_con) == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) { + nm_device_set_autoconnect_retries(device, tries); + retry_time = nm_device_autoconnect_retries_blocked_until(device); + } else { + nm_settings_connection_autoconnect_retries_set(connection, tries); + retry_time = nm_settings_connection_autoconnect_retries_blocked_until(connection); + } if (tries == 0) { /* Schedule a handler to reset retries count */ if (!priv->reset_retries_id) { - gint32 retry_time = - nm_settings_connection_autoconnect_retries_blocked_until(connection); - g_warn_if_fail(retry_time != 0); priv->reset_retries_id = g_timeout_add_seconds(MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()), @@ -1997,13 +2100,25 @@ device_state_changed(NMDevice *device, } if (!blocked) { - tries = nm_settings_connection_autoconnect_retries_get(sett_conn); + s_con = nm_connection_get_setting_connection( + nm_settings_connection_get_connection(sett_conn)); + if (s_con + && nm_setting_connection_get_multi_connect(s_con) + == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) { + if (nm_device_get_autoconnect_retries(device) == -2) + nm_device_set_autoconnect_retries( + device, + nm_settings_connection_autoconnect_retries_get(sett_conn)); + + tries = nm_device_get_autoconnect_retries(device); + } else + tries = nm_settings_connection_autoconnect_retries_get(sett_conn); if (tries > 0) { _LOGD(LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", nm_settings_connection_get_id(sett_conn), tries - 1); - _connection_autoconnect_retries_set(self, sett_conn, tries - 1); + _connection_autoconnect_retries_set(self, sett_conn, device, tries - 1); } else if (tries != 0) { _LOGD(LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left", @@ -2893,7 +3008,7 @@ dispose(GObject *object) } g_hash_table_iter_init(&h_iter, priv->devices); - if (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { + while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { g_hash_table_iter_remove(&h_iter); devices_list_unregister(self, device); } diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 6452d72a..4d8e7bd6 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -5355,59 +5355,41 @@ wired_connection_from_ifcfg(const char *file, shvarFile *ifcfg, GError **error) static gboolean parse_infiniband_p_key(shvarFile *ifcfg, int *out_p_key, char **out_parent, GError **error) { - char *device = NULL, *physdev = NULL, *pkey_id = NULL; - char *ifname = NULL; - int id; - gboolean ret = FALSE; - - device = svGetValueStr_cp(ifcfg, "DEVICE"); - if (!device) { - PARSE_WARNING("InfiniBand connection specified PKEY but not DEVICE"); - goto done; - } + gs_free char *physdev = NULL; + gs_free char *pkey_id = NULL; + int id; physdev = svGetValueStr_cp(ifcfg, "PHYSDEV"); if (!physdev) { - PARSE_WARNING("InfiniBand connection specified PKEY but not PHYSDEV"); - goto done; + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "infiniband connection specified PKEY but not PHYSDEV"); + return FALSE; } pkey_id = svGetValueStr_cp(ifcfg, "PKEY_ID"); if (!pkey_id) { - PARSE_WARNING("InfiniBand connection specified PKEY but not PKEY_ID"); - goto done; + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "infiniband connection specified PKEY but not PKEY_ID"); + return FALSE; } id = _nm_utils_ascii_str_to_int64(pkey_id, 0, 0, 0xFFFF, -1); if (id == -1) { - PARSE_WARNING("invalid InfiniBand PKEY_ID '%s'", pkey_id); - goto done; - } - id = (id | 0x8000); - - ifname = g_strdup_printf("%s.%04x", physdev, (unsigned) id); - if (strcmp(device, ifname) != 0) { - PARSE_WARNING("InfiniBand DEVICE (%s) does not match PHYSDEV+PKEY_ID (%s)", device, ifname); - goto done; - } - - *out_p_key = id; - *out_parent = g_strdup(physdev); - ret = TRUE; - -done: - g_free(device); - g_free(physdev); - g_free(pkey_id); - g_free(ifname); - - if (!ret) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Failed to create InfiniBand setting"); + "invalid infiniband PKEY_ID '%s'", + pkey_id); + return FALSE; } - return ret; + + *out_p_key = id; + *out_parent = g_steal_pointer(&physdev); + return TRUE; } static NMSetting * diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ipoib b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ipoib new file mode 100644 index 00000000..b45da5f7 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ipoib @@ -0,0 +1,9 @@ +TYPE=InfiniBand +PKEY=yes +PKEY_ID=12 +PHYSDEV=ib0 +CONNECTED_MODE=yes +IPADDR=192.168.2.2 +NETMASK=255.255.255.0 +GATEWAY=192.168.2.1 +NAME=ib012 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 9fdae4bd..f9fd7fd5 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -8211,8 +8211,35 @@ test_read_infiniband(void) } static void -test_write_infiniband(void) +test_read_ipoib(void) { + gs_unref_object NMConnection *connection = NULL; + NMSettingInfiniband *s_infiniband; + char *unmanaged = NULL; + const char *transport_mode; + int pkey; + + connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-ipoib", + NULL, + TYPE_INFINIBAND, + &unmanaged); + g_assert(!unmanaged); + + s_infiniband = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_INFINIBAND); + + pkey = nm_setting_infiniband_get_p_key(s_infiniband); + g_assert(pkey); + g_assert_cmpint(pkey, ==, 12); + + transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband); + g_assert(transport_mode); + g_assert_cmpstr(transport_mode, ==, "connected"); +} + +static void +test_write_infiniband(gconstpointer test_data) +{ + const int TEST_IDX = GPOINTER_TO_INT(test_data); nmtst_auto_unlinkfile char *testfile = NULL; gs_unref_object NMConnection *connection = NULL; gs_unref_object NMConnection *reread = NULL; @@ -8223,14 +8250,15 @@ test_write_infiniband(void) const char *mac = "80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22"; guint32 mtu = 65520; NMIPAddress *addr; - GError *error = NULL; + GError *error = NULL; + const char *interface_name = NULL; connection = nm_simple_connection_new(); s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION); g_object_set(s_con, NM_SETTING_CONNECTION_ID, - "Test Write InfiniBand", + "Test Write Infiniband", NM_SETTING_CONNECTION_UUID, nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, @@ -8239,15 +8267,28 @@ test_write_infiniband(void) NM_SETTING_INFINIBAND_SETTING_NAME, NULL); + if (NM_IN_SET(TEST_IDX, 1, 3)) + interface_name = "ib0.000c"; + + g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); + s_infiniband = _nm_connection_new_setting(connection, NM_TYPE_SETTING_INFINIBAND); - g_object_set(s_infiniband, - NM_SETTING_INFINIBAND_MAC_ADDRESS, - mac, - NM_SETTING_INFINIBAND_MTU, - mtu, - NM_SETTING_INFINIBAND_TRANSPORT_MODE, - "connected", - NULL); + g_object_set(s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL); + if (NM_IN_SET(TEST_IDX, 1, 2)) { + g_object_set(s_infiniband, + NM_SETTING_INFINIBAND_MAC_ADDRESS, + mac, + NM_SETTING_INFINIBAND_MTU, + mtu, + NULL); + } else { + g_object_set(s_infiniband, + NM_SETTING_INFINIBAND_P_KEY, + 12, + NM_SETTING_INFINIBAND_PARENT, + "ib0", + NULL); + } s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG); g_object_set(s_ip4, @@ -8267,6 +8308,9 @@ test_write_infiniband(void) s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG); g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + if (nmtst_get_rand_bool()) + nmtst_connection_normalize(connection); + nmtst_assert_connection_verifies(connection); _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile); @@ -8274,6 +8318,8 @@ test_write_infiniband(void) reread = _connection_from_file(testfile, NULL, TYPE_INFINIBAND, NULL); nmtst_assert_connection_equals(connection, TRUE, reread, FALSE); + + g_assert_cmpstr(interface_name, ==, nm_connection_get_interface_name(reread)); } static void @@ -10446,6 +10492,7 @@ main(int argc, char **argv) g_test_add_func(TPATH "wifi/read/wep-no-keys", test_read_wifi_wep_no_keys); g_test_add_func(TPATH "wifi/read/wep-agent-keys", test_read_wifi_wep_agent_keys); g_test_add_func(TPATH "infiniband/read", test_read_infiniband); + g_test_add_func(TPATH "ipoib/read", test_read_ipoib); g_test_add_func(TPATH "vlan/read", test_read_vlan_interface); g_test_add_func(TPATH "vlan/read-flags-1", test_read_vlan_flags_1); g_test_add_func(TPATH "vlan/read-flags-2", test_read_vlan_flags_2); @@ -10582,7 +10629,10 @@ main(int argc, char **argv) g_test_add_func(TPATH "permissions/read", test_read_permissions); g_test_add_func(TPATH "permissions/write", test_write_permissions); g_test_add_func(TPATH "wifi/write-wep-agent-keys", test_write_wifi_wep_agent_keys); - g_test_add_func(TPATH "infiniband/write", test_write_infiniband); + g_test_add_data_func(TPATH "infiniband/write/1", GINT_TO_POINTER(1), test_write_infiniband); + g_test_add_data_func(TPATH "infiniband/write/2", GINT_TO_POINTER(2), test_write_infiniband); + g_test_add_data_func(TPATH "infiniband/write/3", GINT_TO_POINTER(3), test_write_infiniband); + g_test_add_data_func(TPATH "infiniband/write/4", GINT_TO_POINTER(4), test_write_infiniband); g_test_add_func(TPATH "vlan/write", test_write_vlan); g_test_add_func(TPATH "vlan/write-flags", test_write_vlan_flags); g_test_add_func(TPATH "vlan/write-only-vlanid", test_write_vlan_only_vlanid); diff --git a/src/libnm-core-impl/nm-setting-bond-port.c b/src/libnm-core-impl/nm-setting-bond-port.c index 9b41a74f..7ea82a76 100644 --- a/src/libnm-core-impl/nm-setting-bond-port.c +++ b/src/libnm-core-impl/nm-setting-bond-port.c @@ -85,13 +85,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } slave_type = nm_setting_connection_get_slave_type(s_con); - if (!nm_streq0(slave_type, NM_SETTING_BOND_SETTING_NAME)) { + if (slave_type && !nm_streq(slave_type, NM_SETTING_BOND_SETTING_NAME)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("A connection with a '%s' setting must have the slave-type set to '%s'"), + _("A connection with a '%s' setting must have the slave-type set to '%s'. " + "Instead it is '%s'"), NM_SETTING_BOND_PORT_SETTING_NAME, - NM_SETTING_BOND_SETTING_NAME); + NM_SETTING_BOND_SETTING_NAME, + slave_type); g_prefix_error(error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index cdfc7641..18b6fefb 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -764,37 +764,64 @@ _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name) return option_meta->opt_type; } -guint32 -_nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt) +#define _opt_value_as_u64(s_bond, opt, v_max) \ + ({ \ + const OptionMeta *_meta; \ + NMSettingBond *_s_bond = (s_bond); \ + const char *_opt = (opt); \ + const guint64 _v_max = (v_max); \ + const char *_s; \ + guint64 _val; \ + \ + nm_assert(NM_IS_SETTING_BOND(_s_bond)); \ + nm_assert(_opt); \ + \ + _meta = _get_option_meta(_opt); \ + \ + nm_assert(_meta); \ + nm_assert(_meta->opt_type == NM_BOND_OPTION_TYPE_INT); \ + nm_assert(_meta->min < _meta->max); \ + nm_assert(_meta->max <= _v_max); \ + nm_assert(_meta->val); \ + \ + _s = nm_setting_bond_get_option_normalized(_s_bond, _opt); \ + if (_s) { \ + _val = _nm_utils_ascii_str_to_uint64(_s, 10, _meta->min, _meta->max, 0); \ + /* Note that _s is only a valid integer, if the profile verifies. We require + * that the caller only calls these functions on valid profile. */ \ + nm_assert(errno == 0); \ + } else { \ + _val = 0; \ + errno = EINVAL; \ + } \ + \ + _val; \ + }) + +guint8 +_nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt) { - nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); - return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), - 10, - 0, - G_MAXUINT32, - 0); + return _opt_value_as_u64(s_bond, opt, G_MAXUINT8); } guint16 _nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt) { - nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); - return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), - 10, - 0, - G_MAXUINT16, - 0); + return _opt_value_as_u64(s_bond, opt, G_MAXUINT16); } -guint8 -_nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt) +guint32 +_nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt) +{ + return _opt_value_as_u64(s_bond, opt, G_MAXUINT32); +} + +bool +_nm_setting_bond_opt_value_as_intbool(NMSettingBond *s_bond, const char *opt) { - nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); - return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), - 10, - 0, - G_MAXUINT8, - 0); + /* This does not parse the value as a boolean string, instead, it requires + * that it's a number, either "0" or "1". */ + return _opt_value_as_u64(s_bond, opt, 1); } /*****************************************************************************/ diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c index 8b593b97..94794d1e 100644 --- a/src/libnm-core-impl/nm-setting-ip6-config.c +++ b/src/libnm-core-impl/nm-setting-ip6-config.c @@ -832,8 +832,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT, NM_SETTING_PARAM_NONE, NMSettingIP6ConfigPrivate, - addr_gen_mode, - .to_dbus_including_default = TRUE); + addr_gen_mode); /** * NMSettingIP6Config:token: diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 5bdae716..a4e3932a 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -5068,6 +5068,65 @@ test_6lowpan_1(void) /*****************************************************************************/ +static void +test_bond_meta(void) +{ + gs_unref_object NMConnection *con = NULL; + NMSettingBond *set; + char sbuf[200]; + + create_bond_connection(&con, &set); + + g_assert_cmpstr(nm_setting_bond_get_option_normalized(set, NM_SETTING_BOND_OPTION_MODE), + ==, + "balance-rr"); + +#define _A(_nm_setting_bond_opt_value_as_xxx, set, opt, value, errsv) \ + G_STMT_START \ + { \ + g_assert_cmpint(_nm_setting_bond_opt_value_as_xxx((set), (opt)), ==, (value)); \ + g_assert_cmpint(errno, ==, (errsv)); \ + } \ + G_STMT_END + + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_MIIMON, 100, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_UPDELAY, 0, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_DOWNDELAY, 0, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_ARP_INTERVAL, 0, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_RESEND_IGMP, 1, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_MIN_LINKS, 0, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_LP_INTERVAL, 1, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, 1, 0); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, 0, 0); + _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, 0, EINVAL); + _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, 0, EINVAL); + _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, 1, 0); + _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, 0, 0); + _A(_nm_setting_bond_opt_value_as_intbool, set, NM_SETTING_BOND_OPTION_USE_CARRIER, 1, 0); + _A(_nm_setting_bond_opt_value_as_intbool, + set, + NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, + 0, + EINVAL); + + nm_setting_bond_add_option(set, NM_SETTING_BOND_OPTION_ARP_INTERVAL, "5"); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_ARP_INTERVAL, 5, 0); + + nm_setting_bond_add_option(set, + NM_SETTING_BOND_OPTION_ARP_INTERVAL, + nm_sprintf_buf(sbuf, "%d", G_MAXINT)); + _A(_nm_setting_bond_opt_value_as_u32, set, NM_SETTING_BOND_OPTION_ARP_INTERVAL, G_MAXINT, 0); + + nm_setting_bond_add_option(set, NM_SETTING_BOND_OPTION_MODE, "802.3ad"); + _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, 65535, 0); + _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, 0, 0); + + nm_setting_bond_add_option(set, NM_SETTING_BOND_OPTION_MODE, "balance-tlb"); + _A(_nm_setting_bond_opt_value_as_intbool, set, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, 1, 0); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -5185,5 +5244,7 @@ main(int argc, char **argv) g_test_add_func("/libnm/test_setting_metadata", test_setting_metadata); + g_test_add_func("/libnm/test_bond_meta", test_bond_meta); + return g_test_run(); } diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index ee4cc25b..4e1bab47 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -517,9 +517,10 @@ NMConnectionMultiConnect _nm_connection_get_multi_connect(NMConnection *connecti gboolean _nm_setting_bond_option_supported(const char *option, NMBondMode mode); -guint32 _nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt); -guint16 _nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt); guint8 _nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt); +guint16 _nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt); +guint32 _nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt); +bool _nm_setting_bond_opt_value_as_intbool(NMSettingBond *s_bond, const char *opt); /*****************************************************************************/ diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h index acf84ddd..edd872e8 100644 --- a/src/libnm-core-public/nm-version-macros.h +++ b/src/libnm-core-public/nm-version-macros.h @@ -30,7 +30,7 @@ * Evaluates to the micro version number of NetworkManager which this source * compiled against. */ -#define NM_MICRO_VERSION (0) +#define NM_MICRO_VERSION (2) /** * NM_CHECK_VERSION: diff --git a/src/libnm-glib-aux/nm-keyfile-aux.c b/src/libnm-glib-aux/nm-keyfile-aux.c index 1cae28b4..20a4690f 100644 --- a/src/libnm-glib-aux/nm-keyfile-aux.c +++ b/src/libnm-glib-aux/nm-keyfile-aux.c @@ -442,7 +442,7 @@ nm_key_file_db_prune(NMKeyFileDB *self, _LOGD("prune keyfile of old entries: \"%s\"", self->filename); if (!self->groups_pruned) { - /* When we prune the first time, we swap the GKeyfile instance. + /* When we prune the first time, we swap the GKeyFile instance. * The instance loaded from disk might have unrelated groups and * comments. Let's get rid of them by creating a new instance. * diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 624f9a3e..d0885477 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -6621,19 +6621,38 @@ nm_crypto_md5_hash(const guint8 *salt, /*****************************************************************************/ -char * -nm_utils_get_process_exit_status_desc(int status) +const char * +nm_utils_get_process_exit_status_desc_buf(int status, char *buf, gsize buf_len) { + const char *buf0 = buf; + + nm_assert(buf_len == 0 || buf); + + /* This should give a partial sentence, it it can be combined with + * prinft("command XYZ %s.\n", desc) */ + if (WIFEXITED(status)) - return g_strdup_printf("exited with status %d", WEXITSTATUS(status)); + nm_strbuf_append(&buf, &buf_len, "exited with status %d", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) - return g_strdup_printf("killed by signal %d", WTERMSIG(status)); + nm_strbuf_append(&buf, &buf_len, "killed by signal %d", WTERMSIG(status)); else if (WIFSTOPPED(status)) - return g_strdup_printf("stopped by signal %d", WSTOPSIG(status)); + nm_strbuf_append(&buf, &buf_len, "stopped by signal %d", WSTOPSIG(status)); else if (WIFCONTINUED(status)) - return g_strdup("resumed by SIGCONT)"); + nm_strbuf_append(&buf, &buf_len, "resumed by SIGCONT"); else - return g_strdup_printf("exited with unknown status 0x%x", status); + nm_strbuf_append(&buf, &buf_len, "exited with unknown status 0x%x", status); + + return buf0; +} + +char * +nm_utils_get_process_exit_status_desc(int status) +{ + char buf[NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN]; + + nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf)); + + return g_strdup(buf); } /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 3d8eaced..fe7c59f3 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -809,6 +809,8 @@ gssize _nm_strv_find_first(const char *const *list, gssize len, const char *need #define nm_strv_find_first(list, len, needle) \ _nm_strv_find_first(NM_CAST_STRV_CC(list), (len), (needle)) +#define nm_strv_contains(list, len, needle) (nm_strv_find_first((list), (len), (needle)) >= 0) + gboolean nm_strv_has_duplicate(const char *const *list, gssize len, gboolean is_sorted); const char **nm_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated); @@ -1318,6 +1320,8 @@ typedef enum { NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/ NM_UTILS_ERROR_NOT_READY, /*< nick=NotReady >*/ + NM_UTILS_ERROR_COMMAND_FAILED, /*< nick=CommandFailed >*/ + NM_UTILS_ERROR_AMBIGUOUS, /*< nick=Ambiguous >*/ /* the following codes have a special meaning and are exactly used for @@ -3403,6 +3407,10 @@ void nm_crypto_md5_hash(const guint8 *salt, /*****************************************************************************/ +#define NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN 41 + +const char *nm_utils_get_process_exit_status_desc_buf(int status, char *buf, gsize buf_len); + char *nm_utils_get_process_exit_status_desc(int status); gboolean nm_utils_validate_hostname(const char *hostname); diff --git a/src/libnm-glib-aux/nm-str-buf.h b/src/libnm-glib-aux/nm-str-buf.h index 652bc96b..e8b51208 100644 --- a/src/libnm-glib-aux/nm-str-buf.h +++ b/src/libnm-glib-aux/nm-str-buf.h @@ -78,14 +78,14 @@ NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem) ? (size) \ : 0, \ FALSE, \ - (do_bzero_mem)); + (do_bzero_mem)) #define NM_STR_BUF_INIT_ARR(arr, do_bzero_mem) \ NM_STR_BUF_INIT_FULL((arr), \ 0, \ NM_STATIC_ASSERT_EXPR_1(sizeof(arr) > sizeof(char *)) ? sizeof(arr) : 0, \ FALSE, \ - (do_bzero_mem)); + (do_bzero_mem)) void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact); @@ -530,7 +530,10 @@ nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len) char *str = g_steal_pointer(&strbuf->_priv_str); char *result; - result = g_strndup(str, strbuf->_priv_len); + result = g_new(char, strbuf->_priv_len + 1u); + memcpy(result, str, strbuf->_priv_len); + result[strbuf->_priv_len] = '\0'; + if (strbuf->_priv_do_bzero_mem) nm_explicit_bzero(str, strbuf->_priv_len); return result; diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 7d36d64a..cfe70b58 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -970,6 +970,16 @@ test_nm_str_buf(void) } else g_assert(stack_buf != nm_str_buf_get_str(&strbuf)); } + + { + nm_auto_str_buf NMStrBuf s1 = NM_STR_BUF_INIT_A(10, nmtst_get_rand_bool()); + gs_free char *str = NULL; + gsize l; + + nm_str_buf_append_len(&s1, "a\0b", 3); + str = nm_str_buf_finalize(&s1, &l); + g_assert_cmpmem(str, l + 1, "a\0b", 4); + } } /*****************************************************************************/ diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index cd685fe2..eb7c671b 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -1589,11 +1589,8 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) if (tb[IFLA_BOND_MODE]) props->mode = nla_get_u8(tb[IFLA_BOND_MODE]); - if (tb[IFLA_BOND_PRIMARY]) { - props->primary = nla_get_u32(tb[IFLA_BOND_PRIMARY]); - } else if (tb[IFLA_BOND_ACTIVE_SLAVE]) { - props->primary = nla_get_u32(tb[IFLA_BOND_ACTIVE_SLAVE]); - } + if (tb[IFLA_BOND_PRIMARY]) + props->primary = NM_CLAMP((int) nla_get_u32(tb[IFLA_BOND_PRIMARY]), 0, G_MAXINT); if (tb[IFLA_BOND_MIIMON]) { props->miimon = nla_get_u32(tb[IFLA_BOND_MIIMON]); props->miimon_has = TRUE; @@ -1631,12 +1628,8 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) } if (tb[IFLA_BOND_ARP_VALIDATE]) props->arp_validate = nla_get_u32(tb[IFLA_BOND_ARP_VALIDATE]); - if (tb[IFLA_BOND_ARP_ALL_TARGETS]) { - props->arp_all_targets = nla_get_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]); - props->arp_all_targets_has = TRUE; - } else { - props->arp_all_targets_has = FALSE; - } + if (tb[IFLA_BOND_ARP_ALL_TARGETS]) + props->arp_all_targets = nla_get_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]); if (tb[IFLA_BOND_PRIMARY_RESELECT]) props->primary_reselect = nla_get_u8(tb[IFLA_BOND_PRIMARY_RESELECT]); if (tb[IFLA_BOND_FAIL_OVER_MAC]) @@ -2677,7 +2670,7 @@ _wireguard_read_info(NMPlatform *platform /* used only as logging context */ ifindex, wireguard_family_id); - msg = nlmsg_alloc(); + msg = nlmsg_alloc(0); if (!genlmsg_put(msg, NL_AUTO_PORT, @@ -2886,7 +2879,7 @@ _wireguard_create_change_nlmsgs(NMPlatform *platfo again: - msg = nlmsg_alloc(); + msg = nlmsg_alloc(0); if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, @@ -4521,7 +4514,7 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo nla_nest_end(msg, targets); } - if (props->arp_all_targets_has) + if (props->arp_all_targets) NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets); if (props->arp_interval) NLA_PUT_U32(msg, IFLA_BOND_ARP_INTERVAL, props->arp_interval); @@ -4539,7 +4532,7 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo NLA_PUT_U32(msg, IFLA_BOND_PACKETS_PER_SLAVE, props->packets_per_port); if (props->peer_notif_delay_has) NLA_PUT_U32(msg, IFLA_BOND_PEER_NOTIF_DELAY, props->peer_notif_delay); - if (props->primary) + if (props->primary > 0) NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary); if (props->resend_igmp_has) NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp); @@ -4972,7 +4965,8 @@ _nl_msg_new_link_full(uint16_t nlmsg_type, const char *ifname, guint8 family, unsigned flags_mask, - unsigned flags_set) + unsigned flags_set, + size_t len) { nm_auto_nlmsg struct nl_msg *msg = NULL; const struct ifinfomsg ifi = { @@ -4984,7 +4978,7 @@ _nl_msg_new_link_full(uint16_t nlmsg_type, nm_assert(NM_IN_SET(nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK, RTM_SETLINK)); - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); + msg = nlmsg_alloc_new(len ? nlmsg_total_size(NLMSG_HDRLEN + len) : 0, nlmsg_type, nlmsg_flags); if (nlmsg_append_struct(msg, &ifi) < 0) goto nla_put_failure; @@ -5001,7 +4995,7 @@ nla_put_failure: static struct nl_msg * _nl_msg_new_link(uint16_t nlmsg_type, uint16_t nlmsg_flags, int ifindex, const char *ifname) { - return _nl_msg_new_link_full(nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0); + return _nl_msg_new_link_full(nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0, 0); } /* Copied and modified from libnl3's build_addr_msg(). */ @@ -5033,7 +5027,7 @@ _nl_msg_new_address(uint16_t nlmsg_type, nm_assert(NM_IN_SET(family, AF_INET, AF_INET6)); nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWADDR, RTM_DELADDR)); - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); + msg = nlmsg_alloc_new(0, nlmsg_type, nlmsg_flags); addr_len = family == AF_INET ? sizeof(in_addr_t) : sizeof(struct in6_addr); @@ -5140,7 +5134,7 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); + msg = nlmsg_alloc_new(0, nlmsg_type, nlmsg_flags); if (nlmsg_append_struct(msg, &rtmsg) < 0) goto nla_put_failure; @@ -5232,7 +5226,7 @@ _nl_msg_new_routing_rule(uint16_t nlmsg_type, const guint8 addr_size = nm_utils_addr_family_to_size(routing_rule->addr_family); guint32 table; - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); + msg = nlmsg_alloc_new(0, nlmsg_type, nlmsg_flags); table = routing_rule->table; @@ -5351,7 +5345,7 @@ _nl_msg_new_qdisc(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformQdi .tcm_info = qdisc->info, }; - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); + msg = nlmsg_alloc_new(0, nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; @@ -5439,7 +5433,7 @@ _nl_msg_new_tfilter(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformT .tcm_info = tfilter->info, }; - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); + msg = nlmsg_alloc_new(0, nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; @@ -7234,7 +7228,7 @@ _nl_msg_new_dump_rtnl(NMPObjectType obj_type, int preferred_addr_family) nm_assert(klass); nm_assert(klass->rtm_gettype > 0); - nlmsg = nlmsg_alloc_simple(klass->rtm_gettype, NLM_F_DUMP); + nlmsg = nlmsg_alloc_new(0, klass->rtm_gettype, NLM_F_DUMP); if (klass->addr_family != AF_UNSPEC) { /* if the class specifies a particular address family, then it is preferred. */ @@ -7279,7 +7273,7 @@ _nl_msg_new_dump_genl_families(void) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN)); + nlmsg = nlmsg_alloc(nlmsg_total_size(GENL_HDRLEN)); if (!genlmsg_put(nlmsg, NL_AUTO_PORT, @@ -8095,7 +8089,8 @@ link_change_flags(NMPlatform *platform, int ifindex, unsigned flags_mask, unsign nm_platform_link_flags2str(flags_set, s_flags, sizeof(s_flags)), nm_platform_link_flags2str(flags_mask, s_flags2, sizeof(s_flags2))); - nlmsg = _nl_msg_new_link_full(RTM_NEWLINK, 0, ifindex, NULL, AF_UNSPEC, flags_mask, flags_set); + nlmsg = + _nl_msg_new_link_full(RTM_NEWLINK, 0, ifindex, NULL, AF_UNSPEC, flags_mask, flags_set, 0); if (!nlmsg) return -NME_UNSPEC; return do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); @@ -8410,16 +8405,23 @@ link_set_sriov_vfs(NMPlatform *platform, int ifindex, const NMPlatformVF *const { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *list, *info, *vlan_list; - guint i; + guint i = 0; + guint num = 0; + size_t buflen = 0; - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); + while (vfs[num]) + num++; + + /* A single IFLA_VF_INFO shouldn't take more than 200 bytes. */ + buflen = (num + 1) * 200; + nlmsg = _nl_msg_new_link_full(RTM_NEWLINK, 0, ifindex, NULL, AF_UNSPEC, 0, 0, buflen); if (!nlmsg) g_return_val_if_reached(-NME_BUG); if (!(list = nla_nest_start(nlmsg, IFLA_VFINFO_LIST))) goto nla_put_failure; - for (i = 0; vfs[i]; i++) { + for (; vfs[i]; i++) { const NMPlatformVF *vf = vfs[i]; if (!(info = nla_nest_start(nlmsg, IFLA_VF_INFO))) @@ -8492,6 +8494,11 @@ link_set_sriov_vfs(NMPlatform *platform, int ifindex, const NMPlatformVF *const return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); nla_put_failure: + _LOGE("error building SR-IOV VFs netlink message: used %u/%zu bytes for %u/%u VFs", + nlmsg_hdr(nlmsg)->nlmsg_len, + buflen, + i, + num); g_return_val_if_reached(FALSE); } @@ -8506,8 +8513,14 @@ link_set_bridge_vlans(NMPlatform *platform, struct bridge_vlan_info vinfo = {}; guint i; - nlmsg = - _nl_msg_new_link_full(vlans ? RTM_SETLINK : RTM_DELLINK, 0, ifindex, NULL, AF_BRIDGE, 0, 0); + nlmsg = _nl_msg_new_link_full(vlans ? RTM_SETLINK : RTM_DELLINK, + 0, + ifindex, + NULL, + AF_BRIDGE, + 0, + 0, + 0); if (!nlmsg) g_return_val_if_reached(-NME_BUG); @@ -9535,7 +9548,7 @@ tc_delete(NMPlatform *platform, log_tag = "do-delete-tc"; } - msg = nlmsg_alloc_simple(nlmsg_type, NMP_NLM_FLAG_F_ECHO); + msg = nlmsg_alloc_new(0, nlmsg_type, NMP_NLM_FLAG_F_ECHO); if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; @@ -10259,7 +10272,7 @@ mptcp_addr_update(NMPlatform *platform, NMOptionBool add, const NMPlatformMptcpA cmd_str, nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf))); - nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN) + 200); + nlmsg = nlmsg_alloc(nlmsg_total_size(GENL_HDRLEN) + 200); if (!genlmsg_put(nlmsg, NL_AUTO_PORT, @@ -10350,7 +10363,7 @@ mptcp_addrs_dump(NMPlatform *platform) return NULL; } - nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN)); + nlmsg = nlmsg_alloc(nlmsg_total_size(GENL_HDRLEN)); if (!genlmsg_put(nlmsg, NL_AUTO_PORT, diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 36841d56..e08eee5e 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -364,11 +364,22 @@ nla_reserve(struct nl_msg *msg, int attrtype, int attrlen) /*****************************************************************************/ +/** + * Allocate a new netlink message. + * + * Allocates a new netlink message without any further payload. If @len is zero, + * the maximum payload size is set to the size of one memory page. + * + * @return Newly allocated netlink message or NULL. + */ struct nl_msg * -nlmsg_alloc_size(size_t len) +nlmsg_alloc(size_t len) { struct nl_msg *nm; + if (len == 0) + len = nm_utils_getpagesize(); + if (len < sizeof(struct nlmsghdr)) len = sizeof(struct nlmsghdr); else if (len > UINT32_MAX) @@ -384,38 +395,23 @@ nlmsg_alloc_size(size_t len) return nm; } -/** - * Allocate a new netlink message with the default maximum payload size. - * - * Allocates a new netlink message without any further payload. The - * maximum payload size defaults to PAGESIZE or as otherwise specified - * with nlmsg_set_default_size(). - * - * @return Newly allocated netlink message or NULL. - */ -struct nl_msg * -nlmsg_alloc(void) -{ - return nlmsg_alloc_size(nm_utils_getpagesize()); -} - struct nl_msg * nlmsg_alloc_convert(struct nlmsghdr *hdr) { struct nl_msg *nm; - nm = nlmsg_alloc_size(NLMSG_ALIGN(hdr->nlmsg_len)); + nm = nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len)); memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); return nm; } struct nl_msg * -nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags) +nlmsg_alloc_new(size_t size, uint16_t nlmsgtype, uint16_t flags) { struct nl_msg *nm; struct nlmsghdr *new; - nm = nlmsg_alloc(); + nm = nlmsg_alloc(size); new = nm->nm_nlh; new->nlmsg_type = nlmsgtype; new->nlmsg_flags = flags; @@ -928,7 +924,7 @@ genl_ctrl_resolve(struct nl_sock *sk, const char *name) .valid_arg = &response_data, }; - msg = nlmsg_alloc(); + msg = nlmsg_alloc(0); if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, 1)) return -ENOMEM; diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 44ed70af..634be2b4 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -393,13 +393,11 @@ nla_parse_nested(struct nlattr *tb[], /*****************************************************************************/ -struct nl_msg *nlmsg_alloc(void); - -struct nl_msg *nlmsg_alloc_size(size_t max); +struct nl_msg *nlmsg_alloc(size_t len); struct nl_msg *nlmsg_alloc_convert(struct nlmsghdr *hdr); -struct nl_msg *nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags); +struct nl_msg *nlmsg_alloc_new(size_t size, uint16_t nlmsgtype, uint16_t flags); void *nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad); diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index df177485..7d82083c 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -6082,7 +6082,6 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le char sbuf_updelay[30]; char sbuf_downdelay[30]; char sbuf_peer_notif_delay[60]; - char sbuf_arp_all_targets[30]; char sbuf_resend_igmp[30]; char sbuf_lp_interval[30]; char sbuf_tlb_dynamic_lb[30]; @@ -6096,7 +6095,7 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le &len, "bond" " mode %u" - " primary %u" + " primary %d" "%s" /* miimon */ "%s" /* updelay */ "%s" /* downdelay */ @@ -6106,7 +6105,7 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le "%s" /* lp_interval */ " packets_per_port %u" "%s" /* peer_notif_delay */ - "%s" /* arp_all_targets */ + " arp_all_targets %u" " arp_validate %u" " ad_actor_sys_prio %u" " ad_user_port_key %u" @@ -6156,12 +6155,7 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le !lnk->peer_notif_delay_has ? "?" : "", lnk->peer_notif_delay) : "", - lnk->arp_all_targets_has || lnk->arp_all_targets != 0 - ? nm_sprintf_buf(sbuf_arp_all_targets, - " arp_all_targets%s %u", - !lnk->arp_all_targets_has ? "?" : "", - lnk->arp_all_targets) - : "", + lnk->arp_all_targets, lnk->arp_validate, lnk->ad_actor_sys_prio, lnk->ad_user_port_key, @@ -8043,7 +8037,6 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->primary_reselect, obj->xmit_hash_policy, NM_HASH_COMBINE_BOOLS(guint16, - obj->arp_all_targets_has, obj->downdelay_has, obj->lp_interval_has, obj->miimon_has, @@ -8089,7 +8082,6 @@ nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) NM_CMP_FIELD(a, b, mode); NM_CMP_FIELD(a, b, primary_reselect); NM_CMP_FIELD(a, b, xmit_hash_policy); - NM_CMP_FIELD_BOOL(a, b, arp_all_targets_has); NM_CMP_FIELD_BOOL(a, b, downdelay_has); NM_CMP_FIELD_BOOL(a, b, lp_interval_has); NM_CMP_FIELD_BOOL(a, b, miimon_has); diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 90ffbed0..7792bbf5 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -895,6 +895,7 @@ extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; #define NM_BOND_MAX_ARP_TARGETS 16 typedef struct { + int primary; in_addr_t arp_ip_target[NM_BOND_MAX_ARP_TARGETS]; guint32 arp_all_targets; guint32 arp_interval; @@ -905,7 +906,6 @@ typedef struct { guint32 min_links; guint32 packets_per_port; guint32 peer_notif_delay; - guint32 primary; guint32 resend_igmp; guint32 updelay; guint16 ad_actor_sys_prio; @@ -920,7 +920,6 @@ typedef struct { guint8 mode; guint8 primary_reselect; guint8 xmit_hash_policy; - bool arp_all_targets_has : 1; bool downdelay_has : 1; bool lp_interval_has : 1; bool miimon_has : 1; diff --git a/src/libnm-platform/nmp-global-tracker.c b/src/libnm-platform/nmp-global-tracker.c index ea4da284..12869cb2 100644 --- a/src/libnm-platform/nmp-global-tracker.c +++ b/src/libnm-platform/nmp-global-tracker.c @@ -198,7 +198,7 @@ _track_data_hash(gconstpointer data) _track_data_assert(track_data, FALSE); nm_hash_init(&h, 269297543u); - nmp_object_id_hash_update(track_data->obj, &h); + nmp_object_hash_update(track_data->obj, &h); nm_hash_update_val(&h, track_data->user_tag); return nm_hash_complete(&h); } @@ -213,7 +213,7 @@ _track_data_equal(gconstpointer data_a, gconstpointer data_b) _track_data_assert(track_data_b, FALSE); return track_data_a->user_tag == track_data_b->user_tag - && nmp_object_id_equal(track_data_a->obj, track_data_b->obj); + && nmp_object_equal(track_data_a->obj, track_data_b->obj); } static void @@ -253,6 +253,22 @@ _track_obj_data_get_best_data(TrackObjData *obj_data) td_best = track_data; } + if (!td_best) + return NULL; + + /* Always copy the object from the best TrackData to the TrackObjData. It is + * a bit odd that this getter modifies TrackObjData. However, it gives the + * nice property that after calling _track_obj_data_get_best_data() you can + * use obj_data->obj (and get the same as td_best->obj). + * + * This is actually important, because the previous obj_data->obj will have + * the same ID, but it might have minor differences to td_best->obj. + * + * Note that at this point obj_data->obj also might be an object that is no longer + * tracked. Updating the reference will ensure that we don't have such old references + * around and update to use the most appropriate one. */ + nmp_object_ref_set(&obj_data->obj, td_best->obj); + return td_best; } diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index c351f014..cd54df92 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -27,10 +27,9 @@ test_use_symbols(void) (void (*)(void)) nlmsg_hdr, (void (*)(void)) nlmsg_reserve, (void (*)(void)) nla_reserve, - (void (*)(void)) nlmsg_alloc_size, - (void (*)(void)) nlmsg_alloc, (void (*)(void)) nlmsg_alloc_convert, - (void (*)(void)) nlmsg_alloc_simple, + (void (*)(void)) nlmsg_alloc_new, + (void (*)(void)) nlmsg_alloc, (void (*)(void)) nlmsg_free, (void (*)(void)) nlmsg_append, (void (*)(void)) nlmsg_parse, diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 37edd928..c7ee0473 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -86,7 +86,7 @@ _nl80211_alloc_msg(guint16 genl_family_id, int ifindex, int phy, uint8_t cmd, ui { nm_auto_nlmsg struct nl_msg *msg = NULL; - msg = nlmsg_alloc(); + msg = nlmsg_alloc(0); genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (phy != -1) diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c index 675efe5a..03c9581f 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.c +++ b/src/libnm-platform/wpan/nm-wpan-utils.c @@ -79,7 +79,7 @@ _nl802154_alloc_msg(guint16 genl_family_id, int ifindex, uint8_t cmd, uint16_t f { nm_auto_nlmsg struct nl_msg *msg = NULL; - msg = nlmsg_alloc(); + msg = nlmsg_alloc(0); if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0)) goto nla_put_failure; NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex); diff --git a/src/nm-initrd-generator/nm-initrd-generator.h b/src/nm-initrd-generator/nm-initrd-generator.h index 4f33ac65..0761c9bb 100644 --- a/src/nm-initrd-generator/nm-initrd-generator.h +++ b/src/nm-initrd-generator/nm-initrd-generator.h @@ -12,6 +12,9 @@ #define NMI_WAIT_DEVICE_TIMEOUT_MSEC 60000 #define NMI_IP_REQUIRED_TIMEOUT_MSEC 20000 +#define NMI_AUTOCONNECT_PRIORITY_CMDLINE -100 +#define NMI_AUTOCONNECT_PRIORITY_FIRMWARE -200 + static inline int get_ip_address_family(const char *str, gboolean with_prefix) { diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index 34b19e45..36bfdb0b 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -99,6 +99,7 @@ reader_create_connection(Reader *reader, const char *ifname, const char *mac, const char *type_name, + int autoconnect_priority, NMConnectionMultiConnect multi_connect) { NMConnection *connection; @@ -155,6 +156,8 @@ reader_create_connection(Reader *reader, multi_connect, NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, 1, + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, + autoconnect_priority, NULL); if (nm_streq0(type_name, NM_SETTING_INFINIBAND_SETTING_NAME)) { @@ -189,6 +192,7 @@ reader_get_default_connection(Reader *reader) NULL, NULL, NM_SETTING_WIRED_SETTING_NAME, + NMI_AUTOCONNECT_PRIORITY_CMDLINE, NM_CONNECTION_MULTI_CONNECT_MULTIPLE); nm_connection_add_setting(con, nm_setting_wired_new()); reader->default_connection = con; @@ -264,6 +268,7 @@ reader_get_connection(Reader *reader, ifname, mac, type_name, + NMI_AUTOCONNECT_PRIORITY_CMDLINE, NM_CONNECTION_MULTI_CONNECT_SINGLE); } setting = (NMSetting *) nm_connection_get_setting_connection(connection); @@ -1526,6 +1531,7 @@ nmi_cmdline_reader_parse(const char *etc_connections_dir, NULL, bootif, NM_SETTING_WIRED_SETTING_NAME, + NMI_AUTOCONNECT_PRIORITY_FIRMWARE, NM_CONNECTION_MULTI_CONNECT_SINGLE); } else { g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, bootif, NULL); diff --git a/src/nm-initrd-generator/nmi-dt-reader.c b/src/nm-initrd-generator/nmi-dt-reader.c index 554f5c4d..99fe25a2 100644 --- a/src/nm-initrd-generator/nmi-dt-reader.c +++ b/src/nm-initrd-generator/nmi-dt-reader.c @@ -248,6 +248,8 @@ nmi_dt_reader_parse(const char *sysfs_dir) NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_CONNECTION_ID, "OpenFirmware Connection", + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, + NMI_AUTOCONNECT_PRIORITY_FIRMWARE, NULL)); s_ip4 = nm_setting_ip4_config_new(); diff --git a/src/nm-initrd-generator/nmi-ibft-reader.c b/src/nm-initrd-generator/nmi-ibft-reader.c index 5e4b1bb3..3f30e531 100644 --- a/src/nm-initrd-generator/nmi-ibft-reader.c +++ b/src/nm-initrd-generator/nmi-ibft-reader.c @@ -328,6 +328,8 @@ connection_setting_add(GHashTable *nic, id, NM_SETTING_CONNECTION_INTERFACE_NAME, NULL, + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, + NMI_AUTOCONNECT_PRIORITY_FIRMWARE, NULL); g_free(uuid); |