diff options
| author | Michael Biebl <biebl@debian.org> | 2020-07-13 22:03:16 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-07-13 22:03:16 +0200 |
| commit | 136d191f1c96dbae1489fed7c2565f5e1b1f8d40 (patch) | |
| tree | b219a4d9541be3533b0ea62d99a41828e148e3ef /src | |
| parent | 10ae7d8cd706062742d0cdb1803d49909aef9e06 (diff) | |
New upstream version 1.26.0 upstream/1.26.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/devices/nm-device-bond.c | 100 | ||||
| -rw-r--r-- | src/devices/nm-device-ppp.c | 6 | ||||
| -rw-r--r-- | src/devices/nm-device-private.h | 2 | ||||
| -rw-r--r-- | src/devices/nm-device.c | 224 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.c | 15 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovsdb.c | 114 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-broadband.c | 19 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-utils.c | 6 | ||||
| -rw-r--r-- | src/initrd/nm-initrd-generator.c | 31 | ||||
| -rw-r--r-- | src/initrd/nmi-cmdline-reader.c | 49 | ||||
| -rw-r--r-- | src/initrd/tests/test-cmdline-reader.c | 200 | ||||
| -rw-r--r-- | src/ndisc/tests/test-ndisc-fake.c | 79 | ||||
| -rw-r--r-- | src/nm-core-utils.h | 12 | ||||
| -rw-r--r-- | src/nm-ip4-config.c | 55 | ||||
| -rw-r--r-- | src/nm-ip6-config.c | 65 | ||||
| -rw-r--r-- | src/nm-manager.c | 7 | ||||
| -rw-r--r-- | src/nm-policy.c | 6 | ||||
| -rw-r--r-- | src/platform/nm-linux-platform.c | 25 | ||||
| -rw-r--r-- | src/platform/nm-platform.c | 41 | ||||
| -rw-r--r-- | src/platform/nm-platform.h | 6 | ||||
| -rw-r--r-- | src/platform/tests/test-route.c | 18 |
21 files changed, 781 insertions, 299 deletions
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index c15605ce..2fedc753 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -85,6 +85,16 @@ _set_bond_attr (NMDevice *device, const char *attr, const char *value) return ret; } +#define _set_bond_attr_take(device, attr, value) \ + G_STMT_START { \ + gs_free char *_tmp = (value); \ + \ + _set_bond_attr (device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, _tmp); \ + } G_STMT_END + +#define _set_bond_attr_printf(device, attr, fmt, ...) \ + _set_bond_attr_take ((device), (attr), g_strdup_printf (fmt, __VA_ARGS__)) + static gboolean ignore_option (NMSettingBond *s_bond, const char *option, const char *value) { @@ -173,22 +183,59 @@ master_update_slave_connection (NMDevice *self, static void set_arp_targets (NMDevice *device, NMBondMode mode, - const char *value, - const char *delim, - const char *prefix) + const char *cur_arp_ip_target, + const char *new_arp_ip_target) { - gs_free const char **value_v = NULL; + gs_unref_ptrarray GPtrArray *free_list = NULL; + gs_free const char **cur_strv = NULL; + gs_free const char **new_strv = NULL; + gsize cur_len; + gsize new_len; gsize i; + gsize j; - value_v = nm_utils_strsplit_set (value, delim); - if (!value_v) - return; - for (i = 0; value_v[i]; i++) { - gs_free char *tmp = NULL; + cur_strv = nm_utils_strsplit_set_full (cur_arp_ip_target, NM_ASCII_SPACES, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); + new_strv = nm_utils_bond_option_arp_ip_targets_split (new_arp_ip_target); + + cur_len = NM_PTRARRAY_LEN (cur_strv); + new_len = NM_PTRARRAY_LEN (new_strv); + + if (new_len > 0) { + for (j = 0, i = 0; i < new_len; i++) { + const char *s; + in_addr_t a4; - tmp = g_strdup_printf ("%s%s", prefix, value_v[i]); - _set_bond_attr (device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, tmp); + s = new_strv[i]; + if (nm_utils_parse_inaddr_bin (AF_INET, s, NULL, &a4)) { + char sbuf[INET_ADDRSTRLEN]; + + _nm_utils_inet4_ntop (a4, sbuf); + if (!nm_streq (s, sbuf)) { + if (!free_list) + free_list = g_ptr_array_new_with_free_func (g_free); + s = g_strdup (sbuf); + g_ptr_array_add (free_list, (gpointer) s); + } + } + + if (nm_utils_strv_find_first ((char **) new_strv, i, s) < 0) + new_strv[j++] = s; + } + new_strv[j] = NULL; + new_len = j; } + + if ( cur_len == 0 + && new_len == 0) + return; + + if (_nm_utils_strv_equal ((char **) cur_strv, (char **) new_strv)) + return; + + for (i = 0; i < cur_len; i++) + _set_bond_attr_printf (device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "-%s", cur_strv[i]); + for (i = 0; i < new_len; i++) + _set_bond_attr_printf (device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "+%s", new_strv[i]); } /* @@ -201,13 +248,17 @@ set_bond_attr_or_default (NMDevice *device, const char *opt) { NMDeviceBond *self = NM_DEVICE_BOND (device); - const char *value = nm_setting_bond_get_option_or_default (s_bond, opt); + const char *value; - if (value) { - _set_bond_attr (device, opt, value); - } else { - _LOGD (LOGD_BOND, "bond option %s rejected due to incompatibility", opt); + value = nm_setting_bond_get_option_or_default (s_bond, opt); + if (!value) { + if ( _LOGT_ENABLED (LOGD_BOND) + && nm_setting_bond_get_option_by_name (s_bond, opt)) + _LOGT (LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt); + return; } + + _set_bond_attr (device, opt, value); } static gboolean @@ -218,8 +269,7 @@ apply_bonding_config (NMDeviceBond *self) NMSettingBond *s_bond; NMBondMode mode; const char *mode_str; - const char *value; - char *contents; + gs_free char *cur_arp_ip_target = NULL; s_bond = nm_device_get_applied_setting (device, NM_TYPE_SETTING_BOND); g_return_val_if_fail (s_bond, FALSE); @@ -241,13 +291,13 @@ apply_bonding_config (NMDeviceBond *self) set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); /* ARP targets: clear and initialize the list */ - contents = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), - ifindex, - NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - set_arp_targets (device, mode, contents, " \n", "-"); - value = nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - set_arp_targets (device, mode, value, ",", "+"); - g_free (contents); + cur_arp_ip_target = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), + ifindex, + NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + set_arp_targets (device, + mode, + cur_arp_ip_target, + nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM); set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 52784143..cbc87141 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -71,9 +71,13 @@ ppp_ifindex_set (NMPPPManager *ppp_manager, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); + NMDevicePpp *self = NM_DEVICE_PPP (device); gs_free char *old_name = NULL; + gs_free_error GError *error = NULL; - if (!nm_device_take_over_link (device, ifindex, &old_name)) { + if (!nm_device_take_over_link (device, ifindex, &old_name, &error)) { + _LOGW (LOGD_DEVICE | LOGD_PPP, "could not take control of link %d: %s", + ifindex, error->message); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); return; diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 4e260da2..cd72f3d7 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -62,7 +62,7 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar void nm_device_take_down (NMDevice *self, gboolean block); -gboolean nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name); +gboolean nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name, GError **error); gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 90178b68..de09e480 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -411,8 +411,8 @@ typedef struct _NMDevicePrivate { bool v4_route_table_initialized:1; bool v6_route_table_initialized:1; - bool v4_route_table_full_sync_before:1; - bool v6_route_table_full_sync_before:1; + bool v4_route_table_all_sync_before:1; + bool v6_route_table_all_sync_before:1; NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:5; @@ -614,6 +614,7 @@ typedef struct _NMDevicePrivate { SriovOp *pending; /* SR-IOV operation currently running */ SriovOp *next; /* next SR-IOV operation scheduled */ } sriov; + guint sriov_reset_pending; struct { guint timeout_id; @@ -1746,25 +1747,51 @@ nm_device_get_iface (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->iface; } +/** + * nm_device_take_over_link: + * @self: the #NMDevice + * @ifindex: a ifindex + * @old_name: (transfer full): on return, the name of the old link, if + * the link was renamed + * @error: location to store error, or %NULL + * + * Given an existing link, move it under the control of a device. In + * particular, the link will be renamed to match the device name. If the + * link was renamed, the old name is returned in @old_name. + * + * Returns: %TRUE if the device took control of the link, %FALSE otherwise + */ gboolean -nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name) +nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name, GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const NMPlatformLink *plink; NMPlatform *platform; - gboolean up, success = TRUE; - gs_free char *name = NULL; - - g_return_val_if_fail (priv->ifindex <= 0, FALSE); + nm_assert (ifindex > 0); NM_SET_OUT (old_name, NULL); + if ( priv->ifindex > 0 + && priv->ifindex != ifindex) { + nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, + "the device already has ifindex %d", + priv->ifindex); + return FALSE; + } + platform = nm_device_get_platform (self); plink = nm_platform_link_get (platform, ifindex); - if (!plink) + if (!plink) { + nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, + "link %d not found", ifindex); return FALSE; + } if (!nm_streq (plink->name, nm_device_get_iface (self))) { + gboolean up; + gboolean success; + gs_free char *name = NULL; + up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); name = g_strdup (plink->name); @@ -1775,16 +1802,21 @@ nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name) if (up) nm_platform_link_set_up (platform, ifindex, NULL); - if (success) - NM_SET_OUT (old_name, g_steal_pointer (&name)); + if (!success) { + nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, + "failure renaming link %d", ifindex); + return FALSE; + } + + NM_SET_OUT (old_name, g_steal_pointer (&name)); } - if (success) { + if (priv->ifindex != ifindex) { priv->ifindex = ifindex; _notify (self, PROP_IFINDEX); } - return success; + return TRUE; } int @@ -2706,34 +2738,59 @@ _get_route_table_sync_mode_stateful (NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean full_sync_now; - gboolean full_sync_eff; + NMDedupMultiIter ipconf_iter; + gboolean all_sync_now; + gboolean all_sync_eff; + + all_sync_now = _get_route_table (self, addr_family) != 0u; + + if (!all_sync_now) { + /* If there's a local route switch to all-sync in order + * to properly manage the local table */ + if (addr_family == AF_INET) { + const NMPlatformIP4Route *route; - full_sync_now = _get_route_table (self, addr_family) != 0u; + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->con_ip_config_4, &route) { + if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } else { + const NMPlatformIP6Route *route; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->con_ip_config_6, &route) { + if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } + } - if (full_sync_now) - full_sync_eff = TRUE; + if (all_sync_now) + all_sync_eff = TRUE; else { - /* When we change from full-sync to no full-sync, we do a last full-sync one - * more time. For that, we determine the effective full-state based on the - * cached/previous full-sync flag. + /* When we change from all-sync to no all-sync, we do a last all-sync one + * more time. For that, we determine the effective all-state based on the + * cached/previous all-sync flag. * * The purpose of this is to support reapply of route-table (and thus the - * full-sync mode). If reapply toggles from full-sync to no-full-sync, we must + * all-sync mode). If reapply toggles from all-sync to no-all-sync, we must * sync one last time. */ if (addr_family == AF_INET) - full_sync_eff = priv->v4_route_table_full_sync_before; + all_sync_eff = priv->v4_route_table_all_sync_before; else - full_sync_eff = priv->v6_route_table_full_sync_before; + all_sync_eff = priv->v6_route_table_all_sync_before; } if (addr_family == AF_INET) - priv->v4_route_table_full_sync_before = full_sync_now; + priv->v4_route_table_all_sync_before = all_sync_now; else - priv->v6_route_table_full_sync_before = full_sync_now; + priv->v6_route_table_all_sync_before = all_sync_now; - return full_sync_eff - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + return all_sync_eff + ? NM_IP_ROUTE_TABLE_SYNC_MODE_ALL : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; } @@ -3822,6 +3879,10 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); + if ( priv->state < NM_DEVICE_STATE_IP_CONFIG + || priv->state > NM_DEVICE_STATE_ACTIVATED) + return; + g_hash_table_remove_all (priv->ip6_saved_properties); if (priv->dhcp_data_4.client) { @@ -4705,15 +4766,12 @@ sriov_op_cb (GError *error, gpointer user_data) nm_assert (op == priv->sriov.pending); - priv->sriov.pending = NULL; - g_clear_object (&op->cancellable); if (op->callback) op->callback (error, op->callback_data); - nm_assert (!priv->sriov.pending); - + priv->sriov.pending = NULL; nm_g_slice_free (op); if (priv->sriov.next) { @@ -4731,6 +4789,8 @@ sriov_op_queue_op (NMDevice *self, if (priv->sriov.next) { SriovOp *op_next = g_steal_pointer (&priv->sriov.next); + priv->sriov.next = op; + /* Cancel the next operation immediately */ if (op_next->callback) { gs_free_error GError *error = NULL; @@ -4740,17 +4800,10 @@ sriov_op_queue_op (NMDevice *self, } nm_g_slice_free (op_next); + return; + } - if (!priv->sriov.pending) { - /* This (having "next" set but "pending" not) can only happen if we are - * called from inside the callback again. - * - * That means we append the new request as "next" and return. Once - * the callback returns, it will schedule the request. */ - priv->sriov.next = op; - return; - } - } else if (priv->sriov.pending) { + if (priv->sriov.pending) { priv->sriov.next = op; g_cancellable_cancel (priv->sriov.pending->cancellable); return; @@ -13209,7 +13262,8 @@ nm_device_set_ip_config (NMDevice *self, if (IS_IPv4) { success = nm_ip4_config_commit (NM_IP4_CONFIG (new_config), nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, addr_family)); + _get_route_table_sync_mode_stateful (self, + AF_INET)); nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), nm_ip_config_get_ifindex (new_config), ip4_dev_route_blacklist); @@ -13218,7 +13272,8 @@ nm_device_set_ip_config (NMDevice *self, success = nm_ip6_config_commit (NM_IP6_CONFIG (new_config), nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, addr_family), + _get_route_table_sync_mode_stateful (self, + AF_INET6), &temporary_not_available); if (!_rt6_temporary_not_available_set (self, temporary_not_available)) @@ -15463,8 +15518,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; - priv->v4_route_table_full_sync_before = FALSE; - priv->v6_route_table_full_sync_before = FALSE; + priv->v4_route_table_all_sync_before = FALSE; + priv->v6_route_table_all_sync_before = FALSE; priv->default_route_metric_penalty_ip4_has = FALSE; priv->default_route_metric_penalty_ip6_has = FALSE; @@ -15602,17 +15657,19 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_device_update_metered (self); - /* during device cleanup, we want to reset the MAC address of the device - * to the initial state. - * - * We certainly want to do that when reaching the UNMANAGED state... */ - if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED) - nm_device_hw_addr_reset (self, "unmanage"); - else { - /* for other device states (UNAVAILABLE, DISCONNECTED), allow the - * device to overwrite the reset behavior, so that Wi-Fi can set - * a randomized MAC address used during scanning. */ - NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self); + if (ifindex > 0) { + /* during device cleanup, we want to reset the MAC address of the device + * to the initial state. + * + * We certainly want to do that when reaching the UNMANAGED state... */ + if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED) + nm_device_hw_addr_reset (self, "unmanage"); + else { + /* for other device states (UNAVAILABLE, DISCONNECTED), allow the + * device to overwrite the reset behavior, so that Wi-Fi can set + * a randomized MAC address used during scanning. */ + NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self); + } } priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; @@ -15863,27 +15920,51 @@ deactivate_ready (NMDevice *self, NMDeviceStateReason reason) if (priv->dispatcher.call_id) return; - if ( priv->sriov.pending - || priv->sriov.next) + if (priv->sriov_reset_pending > 0) return; - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + if (priv->state == NM_DEVICE_STATE_DEACTIVATING) + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); } static void -sriov_deactivate_cb (GError *error, gpointer user_data) +sriov_reset_on_deactivate_cb (GError *error, gpointer user_data) { NMDevice *self; + NMDevicePrivate *priv; gpointer reason; - if (nm_utils_error_is_cancelled_or_disposing (error)) + nm_utils_user_data_unpack (user_data, &self, &reason); + priv = NM_DEVICE_GET_PRIVATE (self); + nm_assert (priv->sriov_reset_pending > 0); + priv->sriov_reset_pending--; + + if (nm_utils_error_is_cancelled (error)) return; - nm_utils_user_data_unpack (user_data, &self, &reason); deactivate_ready (self, (NMDeviceStateReason) reason); } static void +sriov_reset_on_failure_cb (GError *error, gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (priv->sriov_reset_pending > 0); + priv->sriov_reset_pending--; + + if (nm_utils_error_is_cancelled (error)) + return; + + if (priv->state == NM_DEVICE_STATE_FAILED) { + nm_device_queue_state (self, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + } +} + +static void deactivate_async_ready (NMDevice *self, GError *error, gpointer user_data) @@ -16209,10 +16290,11 @@ _set_state_full (NMDevice *self, if ( priv->ifindex > 0 && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { + priv->sriov_reset_pending++; sriov_op_queue (self, 0, NM_TERNARY_TRUE, - sriov_deactivate_cb, + sriov_reset_on_deactivate_cb, nm_utils_user_data_pack (self, (gpointer) reason)); } } @@ -16264,6 +16346,16 @@ _set_state_full (NMDevice *self, if (sett_conn && !nm_settings_connection_get_timestamp (sett_conn, NULL)) nm_settings_connection_update_timestamp (sett_conn, (guint64) 0); + if ( priv->ifindex > 0 + && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { + priv->sriov_reset_pending++; + sriov_op_queue (self, + 0, + NM_TERNARY_TRUE, + sriov_reset_on_failure_cb, + self); + break; + } /* Schedule the transition to DISCONNECTED. The device can't transition * immediately because we can't change states again from the state * handler for a variety of reasons. @@ -17828,6 +17920,12 @@ dispose (GObject *object) nm_clear_g_source (&priv->concheck_x[0].p_cur_id); nm_clear_g_source (&priv->concheck_x[1].p_cur_id); + nm_assert (!priv->sriov.pending); + if (priv->sriov.next) { + nm_g_slice_free (priv->sriov.next); + priv->sriov.next = NULL; + } + G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); if (nm_clear_g_source (&priv->queued_state.id)) { diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index 10f9fa94..83954cf0 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -104,6 +104,14 @@ link_changed (NMDevice *device, priv->waiting_for_interface = FALSE; if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { + if (!nm_device_hw_addr_set_cloned (device, + nm_device_get_applied_connection (device), + FALSE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; + } nm_device_bring_up (device, TRUE, NULL); nm_device_activate_schedule_stage3_ip_config_start (device); } @@ -176,6 +184,13 @@ act_stage3_ip_config_start (NMDevice *device, return NM_ACT_STAGE_RETURN_POSTPONE; } + if (!nm_device_hw_addr_set_cloned (device, + nm_device_get_applied_connection (device), + FALSE)) { + *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason); } diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index e1865f9d..0b3fa3fd 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -310,6 +310,18 @@ _set_bridge_ports (json_t *params, const char *ifname, json_t *new_ports) ); } +static void +_set_bridge_mac (json_t *params, const char *ifname, const char *mac) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}", + "op", "update", "table", "Bridge", + "row", "other_config", "map", + "hwaddr", mac, + "where", "name", "==", ifname) + ); +} + /** * _expect_port_interfaces: * @@ -353,15 +365,16 @@ _set_port_interfaces (json_t *params, const char *ifname, json_t *new_interfaces * Returns an commands that adds new interface from a given connection. */ static void -_insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_device) +_insert_interface (json_t *params, + NMConnection *interface, + NMDevice *interface_device, + const char *cloned_mac) { const char *type = NULL; NMSettingOvsInterface *s_ovs_iface; NMSettingOvsDpdk *s_ovs_dpdk; NMSettingOvsPatch *s_ovs_patch; json_t *options = json_array (); - gs_free char *cloned_mac = NULL; - gs_free_error GError *error = NULL; json_t *row; guint32 mtu = 0; @@ -377,18 +390,6 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_ mtu = nm_setting_wired_get_mtu (s_wired); } - if (!nm_device_hw_addr_get_cloned (interface_device, - interface, - FALSE, - &cloned_mac, - NULL, - &error)) { - _LOGW ("Cannot determine cloned mac for OVS %s '%s': %s", - "interface", - nm_connection_get_interface_name (interface), - error->message); - } - json_array_append_new (options, json_string ("map")); s_ovs_dpdk = (NMSettingOvsDpdk *) nm_connection_get_setting (interface, @@ -490,7 +491,11 @@ _insert_port (json_t *params, NMConnection *port, json_t *new_interfaces) * Returns an commands that adds new bridge from a given connection. */ static void -_insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, json_t *new_ports) +_insert_bridge (json_t *params, + NMConnection *bridge, + NMDevice *bridge_device, + json_t *new_ports, + const char *cloned_mac) { NMSettingOvsBridge *s_ovs_bridge; const char *fail_mode = NULL; @@ -499,23 +504,9 @@ _insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, j gboolean stp_enable = FALSE; const char *datapath_type = NULL; json_t *row; - gs_free_error GError *error = NULL; - gs_free char *cloned_mac = NULL; s_ovs_bridge = nm_connection_get_setting_ovs_bridge (bridge); - if (!nm_device_hw_addr_get_cloned (bridge_device, - bridge, - FALSE, - &cloned_mac, - NULL, - &error)) { - _LOGW ("Cannot determine cloned mac for OVS %s '%s': %s", - "bridge", - nm_connection_get_interface_name (bridge), - error->message); - } - row = json_object (); if (s_ovs_bridge) { @@ -586,6 +577,9 @@ _add_interface (NMOvsdb *self, json_t *params, const char *bridge_uuid; const char *port_uuid; const char *interface_uuid; + const char *bridge_name; + const char *port_name; + const char *interface_name; OpenvswitchBridge *ovs_bridge = NULL; OpenvswitchPort *ovs_port = NULL; OpenvswitchInterface *ovs_interface = NULL; @@ -596,6 +590,10 @@ _add_interface (NMOvsdb *self, json_t *params, nm_auto_decref_json json_t *interfaces = NULL; nm_auto_decref_json json_t *new_interfaces = NULL; gboolean has_interface = FALSE; + gboolean interface_is_internal; + gs_free char *bridge_cloned_mac = NULL; + gs_free char *interface_cloned_mac = NULL; + GError *error = NULL; int pi; int ii; @@ -606,11 +604,51 @@ _add_interface (NMOvsdb *self, json_t *params, new_ports = json_array (); new_interfaces = json_array (); + bridge_name = nm_connection_get_interface_name (bridge); + port_name = nm_connection_get_interface_name (port); + interface_name = nm_connection_get_interface_name (interface); + interface_is_internal = nm_streq0 (bridge_name, interface_name); + + /* Determine cloned MAC addresses */ + if (!nm_device_hw_addr_get_cloned (bridge_device, + bridge, + FALSE, + &bridge_cloned_mac, + NULL, + &error)) { + _LOGW ("Cannot determine cloned mac for OVS %s '%s': %s", + "bridge", + bridge_name, + error->message); + g_clear_error (&error); + } + + if (!nm_device_hw_addr_get_cloned (interface_device, + interface, + FALSE, + &interface_cloned_mac, + NULL, + &error)) { + _LOGW ("Cannot determine cloned mac for OVS %s '%s': %s", + "interface", + interface_name, + error->message); + g_clear_error (&error); + } + + if ( interface_is_internal + && !bridge_cloned_mac + && interface_cloned_mac) { + _LOGT ("'%s' is a local ovs-interface, the MAC will be set on ovs-bridge '%s'", + interface_name, bridge_name); + bridge_cloned_mac = g_steal_pointer (&interface_cloned_mac); + } + g_hash_table_iter_init (&iter, priv->bridges); while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { json_array_append_new (bridges, json_pack ("[s, s]", "uuid", bridge_uuid)); - if ( g_strcmp0 (ovs_bridge->name, nm_connection_get_interface_name (bridge)) != 0 + if ( g_strcmp0 (ovs_bridge->name, bridge_name) != 0 || g_strcmp0 (ovs_bridge->connection_uuid, nm_connection_get_uuid (bridge)) != 0) continue; @@ -624,7 +662,7 @@ _add_interface (NMOvsdb *self, json_t *params, /* This would be a violation of ovsdb's reference integrity (a bug). */ _LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid); continue; - } else if ( strcmp (ovs_port->name, nm_connection_get_interface_name (port)) != 0 + } else if ( strcmp (ovs_port->name, port_name) != 0 || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) { continue; } @@ -638,7 +676,7 @@ _add_interface (NMOvsdb *self, json_t *params, if (!ovs_interface) { /* This would be a violation of ovsdb's reference integrity (a bug). */ _LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); - } else if ( strcmp (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0 + } else if ( strcmp (ovs_interface->name, interface_name) == 0 && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) { has_interface = TRUE; } @@ -661,12 +699,14 @@ _add_interface (NMOvsdb *self, json_t *params, _expect_ovs_bridges (params, priv->db_uuid, bridges); json_array_append_new (new_bridges, json_pack ("[s, s]", "named-uuid", "rowBridge")); _set_ovs_bridges (params, priv->db_uuid, new_bridges); - _insert_bridge (params, bridge, bridge_device, new_ports); + _insert_bridge (params, bridge, bridge_device, new_ports, bridge_cloned_mac); } else { /* Bridge already exists. */ g_return_if_fail (ovs_bridge); _expect_bridge_ports (params, ovs_bridge->name, ports); - _set_bridge_ports (params, nm_connection_get_interface_name (bridge), new_ports); + _set_bridge_ports (params, bridge_name, new_ports); + if (bridge_cloned_mac && interface_is_internal) + _set_bridge_mac (params, bridge_name, bridge_cloned_mac); } json_array_append_new (new_ports, json_pack ("[s, s]", "named-uuid", "rowPort")); @@ -675,11 +715,11 @@ _add_interface (NMOvsdb *self, json_t *params, /* Port already exists */ g_return_if_fail (ovs_port); _expect_port_interfaces (params, ovs_port->name, interfaces); - _set_port_interfaces (params, nm_connection_get_interface_name (port), new_interfaces); + _set_port_interfaces (params, port_name, new_interfaces); } if (!has_interface) { - _insert_interface (params, interface, interface_device); + _insert_interface (params, interface, interface_device, interface_cloned_mac); json_array_append_new (new_interfaces, json_pack ("[s, s]", "named-uuid", "rowInterface")); } } diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index f172e57f..0929adaf 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -20,9 +20,22 @@ #define NM_MODEM_BROADBAND_MODEM "modem" -#define MODEM_CAPS_3GPP(caps) (caps & (MM_MODEM_CAPABILITY_GSM_UMTS | \ - MM_MODEM_CAPABILITY_LTE | \ - MM_MODEM_CAPABILITY_LTE_ADVANCED)) +static gboolean +MODEM_CAPS_3GPP (MMModemCapability caps) +{ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + /* MM_MODEM_CAPABILITY_LTE_ADVANCED is marked as deprecated since ModemManager 1.14.0. + * + * The flag probably was never used, it certainly isn't used since 1.14.0. + * + * Still, just to be sure, there is no harm in checking it here. Suppress the + * warning, it should have no bad effect. + */ + return NM_FLAGS_ANY (caps, ( MM_MODEM_CAPABILITY_GSM_UMTS + | MM_MODEM_CAPABILITY_LTE + | MM_MODEM_CAPABILITY_LTE_ADVANCED)); + G_GNUC_END_IGNORE_DEPRECATIONS +} #define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index d8e5a653..1c305238 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -440,10 +440,10 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, if (gateway_has) { const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gateway, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gateway, .table_coerced = nm_platform_route_table_coerce (route_table), - .metric = route_metric, + .metric = route_metric, }; nm_ip4_config_add_route (ip4_config, &r, NULL); diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c index ac81dde0..f984ed73 100644 --- a/src/initrd/nm-initrd-generator.c +++ b/src/initrd/nm-initrd-generator.c @@ -130,22 +130,27 @@ main (int argc, char *argv[]) g_hash_table_foreach (connections, output_conn, connections_dir); g_hash_table_destroy (connections); - if (g_mkdir_with_parents (initrd_dir, 0755) != 0) { - errsv = errno; - _LOGW (LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native (errsv)); - return 1; - } + if (dump_to_stdout) { + if (hostname) + g_print ("\n*** Hostname '%s' ***\n", hostname); + } else { + if (g_mkdir_with_parents (initrd_dir, 0755) != 0) { + errsv = errno; + _LOGW (LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native (errsv)); + return 1; + } - if (hostname) { - gs_free char *hostname_file = NULL; - gs_free char *data = NULL; + if (hostname) { + gs_free char *hostname_file = NULL; + gs_free char *data = NULL; - hostname_file = g_strdup_printf ("%s/hostname", initrd_dir); - data = g_strdup_printf ("%s\n", hostname); + hostname_file = g_strdup_printf ("%s/hostname", initrd_dir); + data = g_strdup_printf ("%s\n", hostname); - if (!g_file_set_contents (hostname_file, data, strlen (data), &error)) { - _LOGW (LOGD_CORE, "%s: %s", hostname_file, error->message); - return 1; + if (!g_file_set_contents (hostname_file, data, strlen (data), &error)) { + _LOGW (LOGD_CORE, "%s: %s", hostname_file, error->message); + return 1; + } } } diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 69e5e56d..17f9e1df 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -132,6 +132,7 @@ reader_get_default_connection (Reader *reader) NULL, NM_SETTING_WIRED_SETTING_NAME, NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + nm_connection_add_setting (con, nm_setting_wired_new ()); reader->default_connection = con; } return reader->default_connection; @@ -237,20 +238,24 @@ get_word (char **argument, const char separator) } static void -_base_setting_set (NMConnection *connection, const char *property, const char *value) +connection_set (NMConnection *connection, const char *setting_name, const char *property, const char *value) { NMSetting *setting; - const char *type_name = nm_connection_get_connection_type (connection); - GObjectClass *object_class = g_type_class_ref (nm_setting_lookup_type (type_name)); - GParamSpec *spec = g_object_class_find_property (object_class, property); - - if (!spec) { - _LOGW (LOGD_CORE, "'%s' does not support setting %s", type_name, property); - return; + GType setting_type; + nm_auto_unref_gtypeclass GObjectClass *object_class = NULL; + GParamSpec *spec; + + setting_type = nm_setting_lookup_type (setting_name); + object_class = g_type_class_ref (setting_type); + spec = g_object_class_find_property (object_class, property); + nm_assert (spec); + + setting = nm_connection_get_setting_by_name (connection, setting_name); + if (!setting) { + setting = g_object_new (setting_type, NULL); + nm_connection_add_setting (connection, setting); } - setting = nm_connection_get_setting_by_name (connection, type_name); - if (G_IS_PARAM_SPEC_UINT (spec)) { guint v; @@ -259,14 +264,12 @@ _base_setting_set (NMConnection *connection, const char *property, const char *v || !nm_g_object_set_property_uint (G_OBJECT (setting), property, v, NULL)) { _LOGW (LOGD_CORE, "Could not set property '%s.%s' to '%s'", - type_name, property, value); + setting_name, property, value); } } else if (G_IS_PARAM_SPEC_STRING (spec)) g_object_set (setting, property, value, NULL); else - _LOGW (LOGD_CORE, "Don't know how to set '%s' of %s", property, type_name); - - g_type_class_unref (object_class); + _LOGW (LOGD_CORE, "Don't know how to set '%s' of %s", property, setting_name); } static void @@ -482,17 +485,7 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); } - } else if (nm_streq0 (kind, "dhcp6")) { - g_object_set (s_ip6, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, - NULL); - if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { - g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - } - } else if (nm_streq0 (kind, "auto6")) { + } else if (NM_IN_STRSET (kind, "auto6", "dhcp6")) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, NULL); @@ -577,10 +570,10 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) } if (mtu && *mtu) - _base_setting_set (connection, "mtu", mtu); + connection_set (connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); if (macaddr && *macaddr) - _base_setting_set (connection, "cloned-mac-address", macaddr); + connection_set (connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, macaddr); } static void @@ -635,7 +628,7 @@ reader_parse_master (Reader *reader, NM_SETTING_CONNECTION_MASTER, master, NULL); if (mtu) - _base_setting_set (connection, "mtu", mtu); + connection_set (connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); } while (slaves && *slaves != '\0'); if (argument && *argument) diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 11077055..04594c48 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -138,7 +138,7 @@ test_if_dhcp6 (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); } @@ -569,6 +569,94 @@ test_bond (void) } static void +test_bond_ip (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("bond=bond0:eth0,eth1", + "ip=192.168.1.1::192.168.1.254:24::bond0:none:1480:01:02:03:04:05:06", + "nameserver=4.8.15.16"); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingWired *s_wired; + NMSettingBond *s_bond; + NMIPAddress *ip_addr; + const char *master_uuid; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV, &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); + g_assert_cmpstr (hostname, ==, NULL); + + connection = g_hash_table_lookup (connections, "bond0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bond0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1480); + g_assert_cmpstr (nm_setting_wired_get_cloned_mac_address (s_wired), ==, "01:02:03:04:05:06"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); + ip_addr = nm_setting_ip_config_get_address (s_ip4, 0); + g_assert (ip_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "192.168.1.1"); + g_assert_cmpint (nm_ip_address_get_prefix (ip_addr), ==, 24); + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.254"); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "4.8.15.16"); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 0); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_bond = nm_connection_get_setting_bond (connection); + g_assert (s_bond); + g_assert_cmpint (nm_setting_bond_get_num_options (s_bond), ==, 1); + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, "mode"), ==, "balance-rr"); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_SINGLE); + + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth1"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth1"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_SINGLE); +} + +static void test_bond_default (void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -775,6 +863,71 @@ test_bridge_default (void) } static void +test_bridge_ip (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("ip=bridge123:auto:1280:00:11:22:33:CA:fe", + "bridge=bridge123:eth0,eth1,eth2,eth3,eth4,eth5,eth6,eth7,eth8,eth9"); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingWired *s_wired; + NMSettingBridge *s_bridge; + const char *master_uuid; + gs_free char *hostname = NULL; + guint i; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV, &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 11); + g_assert_cmpstr (hostname, ==, NULL); + + connection = g_hash_table_lookup (connections, "bridge123"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bridge123"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1280); + g_assert_cmpstr (nm_setting_wired_get_cloned_mac_address (s_wired), ==, "00:11:22:33:CA:FE"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + + s_bridge = nm_connection_get_setting_bridge (connection); + g_assert (s_bridge); + + for (i = 0; i < 10; i++) { + char ifname[16]; + + nm_sprintf_buf (ifname, "eth%u", i); + + connection = g_hash_table_lookup (connections, ifname); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, ifname); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, ifname); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_SINGLE); + } +} + +static void test_team (void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -810,7 +963,7 @@ test_team (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); @@ -1064,7 +1217,7 @@ test_rd_znet_no_ip (void) } static void -test_bootif (void) +test_bootif_ip (void) { gs_unref_hashtable GHashTable *connections = NULL; const char *const*ARGV = NM_MAKE_STRV ("BOOTIF=00:53:AB:cd:02:03", @@ -1102,6 +1255,42 @@ test_bootif (void) } static void +test_bootif_no_ip (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("BOOTIF=00:53:AB:cd:02:03"); + NMConnection *connection; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV, &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + g_assert_cmpstr (hostname, ==, NULL); + + connection = g_hash_table_lookup (connections, "default_connection"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "Wired Connection"); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert_cmpstr (nm_setting_wired_get_mac_address (s_wired), ==, "00:53:AB:CD:02:03"); + g_assert (s_wired); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_may_fail (s_ip4)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_may_fail (s_ip6)); +} + +static void test_bootif_hwtype (void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -1244,10 +1433,12 @@ int main (int argc, char **argv) g_test_add_func ("/initrd/cmdline/some_more", test_some_more); g_test_add_func ("/initrd/cmdline/bootdev", test_bootdev); g_test_add_func ("/initrd/cmdline/bond", test_bond); + g_test_add_func ("/initrd/cmdline/bond/ip", test_bond_ip); g_test_add_func ("/initrd/cmdline/bond/default", test_bond_default); g_test_add_func ("/initrd/cmdline/team", test_team); g_test_add_func ("/initrd/cmdline/bridge", test_bridge); g_test_add_func ("/initrd/cmdline/bridge/default", test_bridge_default); + g_test_add_func ("/initrd/cmdline/bridge/ip", test_bridge_ip); g_test_add_func ("/initrd/cmdline/ibft/ip_dev", test_ibft_ip_dev); g_test_add_func ("/initrd/cmdline/ibft/ip", test_ibft_ip); g_test_add_func ("/initrd/cmdline/ibft/rd_iscsi_ibft", test_ibft_rd_iscsi_ibft); @@ -1255,7 +1446,8 @@ int main (int argc, char **argv) g_test_add_func ("/initrd/cmdline/rd_znet", test_rd_znet); g_test_add_func ("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy); g_test_add_func ("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip); - g_test_add_func ("/initrd/cmdline/bootif", test_bootif); + g_test_add_func ("/initrd/cmdline/bootif/ip", test_bootif_ip); + g_test_add_func ("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip); g_test_add_func ("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype); g_test_add_func ("/initrd/cmdline/bootif/off", test_bootif_off); diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index 91fe9802..b65511e0 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -47,44 +47,47 @@ match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts g_assert_cmpint (gw->preference, ==, pref); } -static void -match_address (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, guint32 preferred) -{ - const NMNDiscAddress *a; - char buf[INET6_ADDRSTRLEN]; - - g_assert (rdata); - g_assert_cmpint (idx, <, rdata->addresses_n); - g_assert (rdata->addresses); - - a = &rdata->addresses[idx]; - - g_assert_cmpstr (inet_ntop (AF_INET6, &a->address, buf, sizeof (buf)), ==, addr); - g_assert_cmpint (a->timestamp, ==, ts); - g_assert_cmpint (a->lifetime, ==, lt); - g_assert_cmpint (a->preferred, ==, preferred); -} - -static void -match_route (const NMNDiscData *rdata, guint idx, const char *nw, int plen, const char *gw, guint32 ts, guint32 lt, NMIcmpv6RouterPref pref) -{ - const NMNDiscRoute *route; - char buf[INET6_ADDRSTRLEN]; - - g_assert (rdata); - g_assert_cmpint (idx, <, rdata->routes_n); - g_assert (rdata->routes); - g_assert (plen > 0 && plen <= 128); - - route = &rdata->routes[idx]; - - g_assert_cmpstr (inet_ntop (AF_INET6, &route->network, buf, sizeof (buf)), ==, nw); - g_assert_cmpint ((int) route->plen, ==, plen); - g_assert_cmpstr (inet_ntop (AF_INET6, &route->gateway, buf, sizeof (buf)), ==, gw); - g_assert_cmpint (route->timestamp, ==, ts); - g_assert_cmpint (route->lifetime, ==, lt); - g_assert_cmpint (route->preference, ==, pref); -} +#define match_address(rdata, idx, addr, ts, lt, pref) \ + G_STMT_START { \ + const NMNDiscData *_rdata = (rdata); \ + guint _idx = (idx); \ + const NMNDiscAddress *_a; \ + guint _ts = (ts); \ + \ + g_assert (_rdata); \ + g_assert_cmpint (_idx, <, _rdata->addresses_n); \ + g_assert (_rdata->addresses); \ + \ + _a = &_rdata->addresses[_idx]; \ + \ + nmtst_assert_ip6_address (&_a->address, (addr)); \ + g_assert_cmpint (_a->timestamp, >=, _ts); \ + g_assert_cmpint (_a->timestamp, <=, _ts + 1); \ + g_assert_cmpint (_a->timestamp + _a->lifetime, ==, _ts + (lt)); \ + g_assert_cmpint (_a->timestamp + _a->preferred, ==, _ts + (pref)); \ + } G_STMT_END + +#define match_route(rdata, idx, nw, pl, gw, ts, lt, pref) \ + G_STMT_START { \ + const NMNDiscData *_rdata = (rdata); \ + guint _idx = (idx); \ + const NMNDiscRoute *_r; \ + int _plen = (pl); \ + \ + g_assert (_rdata); \ + g_assert_cmpint (_idx, <, _rdata->routes_n); \ + g_assert (_rdata->routes); \ + g_assert (_plen > 0 && _plen <= 128); \ + \ + _r = &_rdata->routes[idx]; \ + \ + nmtst_assert_ip6_address (&_r->network, (nw)); \ + g_assert_cmpint ((int) _r->plen, ==, _plen); \ + nmtst_assert_ip6_address (&_r->gateway, (gw)); \ + g_assert_cmpint (_r->timestamp, ==, (ts)); \ + g_assert_cmpint (_r->lifetime, ==, (lt)); \ + g_assert_cmpint (_r->preference, ==, (pref)); \ + } G_STMT_END static void match_dns_server (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt) diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index fae7adbf..55792d57 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -156,8 +156,13 @@ double nm_utils_exp10 (gint16 e); * nm_utils_ip6_route_metric_normalize: * @metric: the route metric * - * For IPv6 route, kernel treats the value 0 as IP6_RT_PRIO_USER (1024). - * Thus, when comparing metric (values), we want to treat zero as NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6. + * For IPv6 route, when adding a route via netlink, kernel treats the value 0 as IP6_RT_PRIO_USER (1024). + * So, user space cannot add routes with such a metric, and 0 gets "normalized" + * to NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6. + * + * Note that kernel itself can add IPv6 routes with metric zero. Also, you can delete + * them, but mostly because with `ip -6 route delete ... metric 0` the 0 acts as a wildcard + * and kills the first matching route. * * Returns: @metric, if @metric is not zero, otherwise 1024. */ @@ -174,9 +179,8 @@ nm_utils_ip_route_metric_normalize (int addr_family, guint32 metric) } static inline guint32 -nm_utils_ip_route_metric_penalize (int addr_family, guint32 metric, guint32 penalty) +nm_utils_ip_route_metric_penalize (guint32 metric, guint32 penalty) { - metric = nm_utils_ip_route_metric_normalize (addr_family, metric); if (metric < G_MAXUINT32 - penalty) return metric + penalty; return G_MAXUINT32; diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 62b41478..490296c8 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -393,10 +393,6 @@ nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Conf const NMPObject * _nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp) { - int addr_family; - int c; - guint metric_cur, metric_cmp; - nm_assert ( !obj_cur || NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cur), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert ( !obj_cmp @@ -410,17 +406,20 @@ _nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NM * @obj_cmp is also a default route and returns the best of both. */ if ( obj_cmp && nm_ip_config_best_default_route_is (obj_cmp)) { + guint32 metric_cur, metric_cmp; + if (!obj_cur) return obj_cmp; - addr_family = NMP_OBJECT_GET_CLASS (obj_cmp)->addr_family; - metric_cur = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric); - metric_cmp = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric); + metric_cur = NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric; + metric_cmp = NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric; if (metric_cmp < metric_cur) return obj_cmp; if (metric_cmp == metric_cur) { + int c; + /* Routes have the same metric. We still want to deterministically * prefer one or the other. It's important to consistently choose one * or the other, so that the order doesn't matter how routes are added @@ -672,6 +671,28 @@ nm_ip4_config_update_routes_metric (NMIP4Config *self, gint64 metric) g_object_thaw_notify (G_OBJECT (self)); } +static void +_add_local_route_from_addr4 (NMIP4Config *self, + const NMPlatformIP4Address *addr, + int ifindex) +{ + nm_auto_nmpobj NMPObject *r = NULL; + NMPlatformIP4Route *route; + + r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL); + route = NMP_OBJECT_CAST_IP4_ROUTE (r); + route->ifindex = ifindex; + route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; + route->network = addr->address; + route->plen = 32; + route->pref_src = addr->address; + route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); + route->scope_inv = nm_platform_route_scope_inv (RT_SCOPE_HOST); + + _add_route (self, r, NULL, NULL); +} + void nm_ip4_config_add_dependent_routes (NMIP4Config *self, guint32 route_table, @@ -708,6 +729,8 @@ nm_ip4_config_add_dependent_routes (NMIP4Config *self, if (my_addr->external) continue; + _add_local_route_from_addr4 (self, my_addr, ifindex); + if (_ipv4_is_zeronet (network)) { /* Kernel doesn't add device-routes for destinations that * start with 0.x.y.z. Skip them. */ @@ -1002,6 +1025,7 @@ nm_ip4_config_merge_setting (NMIP4Config *self, for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP4Route route; + gint64 m; if (nm_ip_route_get_family (s_route) != AF_INET) { nm_assert_not_reached (); @@ -1015,10 +1039,11 @@ nm_ip4_config_merge_setting (NMIP4Config *self, nm_assert (route.plen <= 32); nm_ip_route_get_next_hop_binary (s_route, &route.gateway); - if (nm_ip_route_get_metric (s_route) == -1) + m = nm_ip_route_get_metric (s_route); + if (m < 0) route.metric = route_metric; else - route.metric = nm_ip_route_get_metric (s_route); + route.metric = m; route.rt_source = NM_IP_CONFIG_SOURCE_USER; route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); @@ -1141,8 +1166,10 @@ nm_ip4_config_create_setting (const NMIP4Config *self) continue; s_route = nm_ip_route_new_binary (AF_INET, - &route->network, route->plen, - &route->gateway, route->metric, + &route->network, + route->plen, + &route->gateway, + route->metric, NULL); nm_setting_ip_config_add_route (s_ip4, s_route); nm_ip_route_unref (s_route); @@ -1227,7 +1254,7 @@ nm_ip4_config_merge (NMIP4Config *dst, if (default_route_metric_penalty) { NMPlatformIP4Route r = *r_src; - r.metric = nm_utils_ip_route_metric_penalize (AF_INET, r.metric, default_route_metric_penalty); + r.metric = nm_utils_ip_route_metric_penalize (r.metric, default_route_metric_penalty); _add_route (dst, NULL, &r, NULL); continue; } @@ -1459,7 +1486,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, * the routes. */ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_src); rr = NMP_OBJECT_CAST_IP4_ROUTE (&o_lookup_copy); - rr->metric = nm_utils_ip_route_metric_penalize (AF_INET, rr->metric, default_route_metric_penalty); + rr->metric = nm_utils_ip_route_metric_penalize (rr->metric, default_route_metric_penalty); } else o_lookup = o_src; @@ -1610,7 +1637,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, * the routes. */ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_dst); rr = NMP_OBJECT_CAST_IP4_ROUTE (&o_lookup_copy); - rr->metric = nm_utils_ip_route_metric_penalize (AF_INET, rr->metric, default_route_metric_penalty); + rr->metric = nm_utils_ip_route_metric_penalize (rr->metric, default_route_metric_penalty); } else o_lookup = o_dst; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index b60e8057..4911ec1d 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -456,6 +456,42 @@ nm_ip6_config_update_routes_metric (NMIP6Config *self, gint64 metric) g_object_thaw_notify (G_OBJECT (self)); } +static void +_add_multicast_route6 (NMIP6Config *self, int ifindex) +{ + nm_auto_nmpobj NMPObject *r = NULL; + NMPlatformIP6Route *route; + + r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + route = NMP_OBJECT_CAST_IP6_ROUTE (r); + route->ifindex = ifindex; + route->network.s6_addr[0] = 0xffu; + route->plen = 8; + route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + route->type_coerced = nm_platform_route_type_coerce (RTN_UNICAST); + route->metric = 256; + + _add_route (self, r, NULL, NULL); +} + +static void +_add_local_route_from_addr6 (NMIP6Config *self, const NMPlatformIP6Address *addr, int ifindex) +{ + nm_auto_nmpobj NMPObject *r = NULL; + NMPlatformIP6Route *route; + + r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + route = NMP_OBJECT_CAST_IP6_ROUTE (r); + route->ifindex = ifindex; + route->network = addr->address; + route->plen = 128; + route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); + route->metric = 0; + + _add_route (self, r, NULL, NULL); +} + void nm_ip6_config_add_dependent_routes (NMIP6Config *self, guint32 route_table, @@ -476,6 +512,9 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, * * For manually added IPv6 routes, add the device routes explicitly. */ + /* Pre-generate multicast route */ + _add_multicast_route6 (self, ifindex); + nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { NMPlatformIP6Route *route; gboolean has_peer; @@ -483,6 +522,10 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, if (my_addr->external) continue; + + /* Pre-generate local route added by kernel */ + _add_local_route_from_addr6 (self, my_addr, ifindex); + if (NM_FLAGS_HAS (my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; if (my_addr->plen == 0) @@ -650,6 +693,7 @@ nm_ip6_config_merge_setting (NMIP6Config *self, for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP6Route route; + gint64 m; if (nm_ip_route_get_family (s_route) != AF_INET6) { nm_assert_not_reached (); @@ -663,10 +707,11 @@ nm_ip6_config_merge_setting (NMIP6Config *self, nm_assert (route.plen <= 128); nm_ip_route_get_next_hop_binary (s_route, &route.gateway); - if (nm_ip_route_get_metric (s_route) == -1) + m = nm_ip_route_get_metric (s_route); + if (m < 0) route.metric = route_metric; else - route.metric = nm_ip_route_get_metric (s_route); + route.metric = nm_utils_ip6_route_metric_normalize (m); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); @@ -797,8 +842,10 @@ nm_ip6_config_create_setting (const NMIP6Config *self) continue; s_route = nm_ip_route_new_binary (AF_INET6, - &route->network, route->plen, - &route->gateway, route->metric, + &route->network, + route->plen, + &route->gateway, + route->metric, NULL); nm_setting_ip_config_add_route (s_ip6, s_route); nm_ip_route_unref (s_route); @@ -882,7 +929,7 @@ nm_ip6_config_merge (NMIP6Config *dst, if (default_route_metric_penalty) { NMPlatformIP6Route r = *r_src; - r.metric = nm_utils_ip_route_metric_penalize (AF_INET6, r.metric, default_route_metric_penalty); + r.metric = nm_utils_ip_route_metric_penalize (r.metric, default_route_metric_penalty); _add_route (dst, NULL, &r, NULL); continue; } @@ -1052,7 +1099,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, * the routes. */ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_src); rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy); - rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty); + rr->metric = nm_utils_ip_route_metric_penalize (rr->metric, default_route_metric_penalty); } else o_lookup = o_src; @@ -1173,7 +1220,7 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, * the routes. */ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_dst); rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy); - rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty); + rr->metric = nm_utils_ip_route_metric_penalize (rr->metric, default_route_metric_penalty); } else o_lookup = o_dst; @@ -2052,8 +2099,8 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, if (!nm_utils_ip6_address_same_prefix (host, &item->network, item->plen)) continue; - if (best_route && - nm_utils_ip6_route_metric_normalize (best_route->metric) <= nm_utils_ip6_route_metric_normalize (item->metric)) + if ( best_route + && best_route->metric <= item->metric) continue; best_route = item; diff --git a/src/nm-manager.c b/src/nm-manager.c index ae78b7c9..92112532 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3044,10 +3044,9 @@ _get_best_connectivity (NMManager *self, int addr_family) gint64 metric; r = nm_device_get_best_default_route (dev, addr_family); - if (r) { - metric = nm_utils_ip_route_metric_normalize (addr_family, - NMP_OBJECT_CAST_IP_ROUTE (r)->metric); - } else { + if (r) + metric = NMP_OBJECT_CAST_IP_ROUTE (r)->metric; + else { /* if all devices have no default-route, we still include the best * of all connectivity state of all the devices. */ metric = G_MAXINT64; diff --git a/src/nm-policy.c b/src/nm-policy.c index 2a9f6c05..62ead242 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -442,14 +442,12 @@ get_best_active_connection (NMPolicy *self, * * In this case, is it really the best device? Why do we even need the best * device?? */ - metric = nm_utils_ip_route_metric_normalize (addr_family, - NMP_OBJECT_CAST_IP_ROUTE (r)->metric); + metric = NMP_OBJECT_CAST_IP_ROUTE (r)->metric; is_fully_activated = TRUE; } else if ( !fully_activated && (connection = nm_device_get_applied_connection (device)) && nm_utils_connection_has_default_route (connection, addr_family, NULL)) { - metric = nm_utils_ip_route_metric_normalize (addr_family, - nm_device_get_route_metric (device, addr_family)); + metric = nm_device_get_route_metric (device, addr_family); is_fully_activated = FALSE; } else continue; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 710a6f91..fbcc2b31 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3398,6 +3398,7 @@ rta_multipath_done: obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + obj->ip_route.type_coerced = nm_platform_route_type_coerce (rtm->rtm_type); obj->ip_route.table_coerced = nm_platform_route_table_coerce ( tb[RTA_TABLE] ? nla_get_u32 (tb[RTA_TABLE]) : (guint32) rtm->rtm_table); @@ -7249,7 +7250,7 @@ link_supports_sriov (NMPlatform *platform, int ifindex) nm_auto_pop_netns NMPNetns *netns = NULL; nm_auto_close int dirfd = -1; char ifname[IFNAMSIZ]; - int total = -1; + int num = -1; if (!nm_platform_netns_push (platform, &netns)) return FALSE; @@ -7258,13 +7259,13 @@ link_supports_sriov (NMPlatform *platform, int ifindex) if (dirfd < 0) return FALSE; - total = nm_platform_sysctl_get_int32 (platform, - NMP_SYSCTL_PATHID_NETDIR (dirfd, - ifname, - "device/sriov_totalvfs"), - -1); + num = nm_platform_sysctl_get_int32 (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + -1); - return total > 0; + return num != -1; } static int @@ -7407,15 +7408,7 @@ link_set_sriov_params_async (NMPlatform *platform, ifname, "device/sriov_totalvfs"), 10, 0, G_MAXUINT, 0); - if (errno) { - g_set_error (&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "failed reading sriov_totalvfs value: %s", - nm_strerror_native (errno)); - goto out_idle; - } - if (num_vfs > total) { + if (!errno && num_vfs > total) { _LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); num_vfs = total; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index c8b8c6e8..4702ba97 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4314,6 +4314,13 @@ nm_platform_ip_route_sync (NMPlatform *self, continue; } + if ( !IS_IPv4 + && NMP_OBJECT_CAST_IP6_ROUTE (conf_o)->metric == 0) { + /* User space cannot add routes with metric 0. However, kernel can, and we might track such + * routes in @route as they are present external. Skip them silently. */ + continue; + } + plat_entry = nm_platform_lookup_entry (self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o); @@ -4571,7 +4578,6 @@ nm_platform_ip_route_normalize (int addr_family, r6->table_coerced = nm_platform_route_table_coerce (nm_platform_route_table_uncoerce (r6->table_coerced, TRUE)); nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen); r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source), - r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric); nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen); break; default: @@ -6083,11 +6089,11 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; - char str_type[30]; char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; + char str_type[30]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -6098,7 +6104,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, - "%s" /* type */ + "type %s " /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6116,7 +6122,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi "%s" /* initrwnd */ "%s" /* mtu */ "", - route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", + nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), str_type, sizeof (str_type)), route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen, @@ -6186,7 +6192,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, - "%s" /* type */ + "type %s " /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6204,7 +6210,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi "%s" /* mtu */ "%s" /* pref */ "", - route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", + nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), str_type, sizeof (str_type)), route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen, @@ -7463,7 +7469,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), *nm_utils_ip6_address_clear_host_address (&a1, &obj->network, obj->plen), obj->plen, - nm_utils_ip6_route_metric_normalize (obj->metric), + obj->metric, *nm_utils_ip6_address_clear_host_address (&a2, &obj->src, obj->src_plen), obj->src_plen); break; @@ -7473,7 +7479,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), *nm_utils_ip6_address_clear_host_address (&a1, &obj->network, obj->plen), obj->plen, - nm_utils_ip6_route_metric_normalize (obj->metric), + obj->metric, *nm_utils_ip6_address_clear_host_address (&a2, &obj->src, obj->src_plen), obj->src_plen, /* on top of WEAK_ID: */ @@ -7487,7 +7493,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo obj->ifindex, *nm_utils_ip6_address_clear_host_address (&a1, &obj->network, obj->plen), obj->plen, - nm_utils_ip6_route_metric_normalize (obj->metric), + obj->metric, obj->gateway, obj->pref_src, *nm_utils_ip6_address_clear_host_address (&a2, &obj->src, obj->src_plen), @@ -7550,7 +7556,7 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route nm_platform_route_table_uncoerce (b->table_coerced, TRUE)); NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen)); NM_CMP_FIELD (a, b, plen); - NM_CMP_DIRECT (nm_utils_ip6_route_metric_normalize (a->metric), nm_utils_ip6_route_metric_normalize (b->metric)); + NM_CMP_FIELD (a, b, metric); NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->src, &b->src, MIN (a->src_plen, b->src_plen)); NM_CMP_FIELD (a, b, src_plen); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { @@ -7573,10 +7579,7 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route else NM_CMP_FIELD_IN6ADDR (a, b, network); NM_CMP_FIELD (a, b, plen); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - NM_CMP_DIRECT (nm_utils_ip6_route_metric_normalize (a->metric), nm_utils_ip6_route_metric_normalize (b->metric)); - else - NM_CMP_FIELD (a, b, metric); + NM_CMP_FIELD (a, b, metric); NM_CMP_FIELD_IN6ADDR (a, b, gateway); NM_CMP_FIELD_IN6ADDR (a, b, pref_src); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { @@ -8054,14 +8057,6 @@ nm_platform_netns_push (NMPlatform *self, NMPNetns **netns) /*****************************************************************************/ -static guint32 -_vtr_v4_metric_normalize (guint32 metric) -{ - return metric; -} - -/*****************************************************************************/ - const _NMPlatformVTableRouteUnion nm_platform_vtable_route = { .v4 = { .is_ip4 = TRUE, @@ -8070,7 +8065,6 @@ const _NMPlatformVTableRouteUnion nm_platform_vtable_route = { .sizeof_route = sizeof (NMPlatformIP4Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string, - .metric_normalize = _vtr_v4_metric_normalize, }, .v6 = { .is_ip4 = FALSE, @@ -8079,7 +8073,6 @@ const _NMPlatformVTableRouteUnion nm_platform_vtable_route = { .sizeof_route = sizeof (NMPlatformIP6Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string, - .metric_normalize = nm_utils_ip6_route_metric_normalize, }, }; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 3e6ef84c..2b5d4914 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -382,7 +382,10 @@ typedef union { #define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0 /* Default value for adding an IPv6 route. This is also what iproute2 does. - * Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024). */ + * Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024). + * + * Note that kernel doesn't allow adding IPv6 routes with metric zero via netlink. + * It however can itself add routes with metric zero. */ #define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024 /* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user @@ -720,7 +723,6 @@ typedef struct { gsize sizeof_route; int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type); const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len); - guint32 (*metric_normalize) (guint32 metric); } NMPlatformVTableRoute; typedef union { diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 19debfb5..42b5baf0 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -319,7 +319,7 @@ test_ip6_route (void) guint8 plen = 64; struct in6_addr gateway, pref_src; /* Choose a high metric so that we hopefully don't conflict. */ - int metric = 22987; + const int metric = 22987; int mss = 1000; inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); @@ -328,7 +328,7 @@ test_ip6_route (void) g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)); - accept_signals (route_added, 0, 2); + accept_signals (route_added, 0, 3); _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 200, ifindex, 1, &pref_src); @@ -365,7 +365,7 @@ test_ip6_route (void) rts[0].ifindex = ifindex; rts[0].gateway = in6addr_any; rts[0].pref_src = in6addr_any; - rts[0].metric = nm_utils_ip6_route_metric_normalize (metric); + rts[0].metric = metric; rts[0].mss = mss; rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[1].network = network; @@ -373,7 +373,7 @@ test_ip6_route (void) rts[1].ifindex = ifindex; rts[1].gateway = gateway; rts[1].pref_src = pref_src; - rts[1].metric = nm_utils_ip6_route_metric_normalize (metric); + rts[1].metric = metric; rts[1].mss = mss; rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[2].network = in6addr_any; @@ -381,7 +381,7 @@ test_ip6_route (void) rts[2].ifindex = ifindex; rts[2].gateway = gateway; rts[2].pref_src = in6addr_any; - rts[2].metric = nm_utils_ip6_route_metric_normalize (metric); + rts[2].metric = metric; rts[2].mss = mss; g_assert_cmpint (routes->len, ==, 3); nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); @@ -586,7 +586,13 @@ test_ip6_route_get (void) NMTST_WAIT_ASSERT (100, { nmtstp_wait_for_signal (NM_PLATFORM_GET, 10); - if (nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet6_from_string ("fd01:abcd::"), 64, 0, NULL, 0)) + if (nmtstp_ip6_route_get (NM_PLATFORM_GET, + ifindex, + nmtst_inet6_from_string ("fd01:abcd::"), + 64, + NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, + NULL, + 0)) break; }); |