diff options
Diffstat (limited to 'src/core')
231 files changed, 9047 insertions, 3594 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index f5b7666b..6f4c60f8 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -419,8 +419,8 @@ route_compare(NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) nm_assert_not_reached(); if (!inet_pton(family, nm_ip_route_get_dest(route2), &a2)) nm_assert_not_reached(); - nm_utils_ipx_address_clear_host_address(family, &a1, NULL, plen); - nm_utils_ipx_address_clear_host_address(family, &a2, NULL, plen); + nm_ip_addr_clear_host_address(family, &a1, NULL, plen); + nm_ip_addr_clear_host_address(family, &a2, NULL, plen); NM_CMP_DIRECT_MEMCMP(&a1, &a2, nm_utils_addr_family_to_size(family)); return 0; @@ -1382,11 +1382,16 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_SCOPE, scope, BYTE, byte, RT_SCOPE_NOWHERE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_WEIGHT, r4->weight, UINT32, uint32, 0); r4->scope_inv = nm_platform_route_scope_inv(scope); } + /* Note that for IPv4 routes in kernel, the onlink flag can be set for + * each next hop separately (rtnh_flags). Not for NetworkManager. We can + * only merge routes as ECMP routes (when setting a weight) if they all + * share the same onlink flag. See NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID. + * That simplifies the code. */ GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); - r->r_rtm_flags = ((onlink) ? (unsigned) RTNH_F_ONLINK : 0u); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_ADVMSS, r->mss, UINT32, uint32, 0); @@ -1418,11 +1423,11 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { int prefix; - if (nm_utils_parse_inaddr_prefix_bin(addr_family, - g_variant_get_string(variant, NULL), - NULL, - &addr, - &prefix)) { + if (nm_inet_parse_with_prefix_bin(addr_family, + g_variant_get_string(variant, NULL), + NULL, + &addr, + &prefix)) { if (prefix < 0) prefix = 128; r6->src = addr.addr6; @@ -1444,7 +1449,7 @@ nm_utils_ip_addresses_to_dbus(int addr_family, const int IS_IPv4 = NM_IS_IPv4(addr_family); GVariantBuilder builder_data; GVariantBuilder builder_legacy; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; NMDedupMultiIter iter; const NMPObject *obj; guint i; @@ -1479,8 +1484,7 @@ nm_utils_ip_addresses_to_dbus(int addr_family, &addr_builder, "{sv}", "address", - g_variant_new_string( - nm_utils_inet_ntop(addr_family, address->ax.address_ptr, addr_str))); + g_variant_new_string(nm_inet_ntop(addr_family, address->ax.address_ptr, addr_str))); g_variant_builder_add(&addr_builder, "{sv}", @@ -1497,11 +1501,10 @@ nm_utils_ip_addresses_to_dbus(int addr_family, p = &address->a6.peer_address; } if (p) { - g_variant_builder_add( - &addr_builder, - "{sv}", - "peer", - g_variant_new_string(nm_utils_inet_ntop(addr_family, p, addr_str))); + g_variant_builder_add(&addr_builder, + "{sv}", + "peer", + g_variant_new_string(nm_inet_ntop(addr_family, p, addr_str))); } if (IS_IPv4) { @@ -1559,7 +1562,7 @@ nm_utils_ip_routes_to_dbus(int addr_family, const NMPObject *obj; GVariantBuilder builder_data; GVariantBuilder builder_legacy; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; nm_assert_addr_family(addr_family); @@ -1580,14 +1583,12 @@ nm_utils_ip_routes_to_dbus(int addr_family, nm_assert(r); nm_assert(r->rx.plen <= 8u * nm_utils_addr_family_to_size(addr_family)); nm_assert(!IS_IPv4 - || r->r4.network - == nm_utils_ip4_address_clear_host_address(r->r4.network, r->r4.plen)); - nm_assert( - IS_IPv4 - || (memcmp(&r->r6.network, - nm_utils_ip6_address_clear_host_address(&n, &r->r6.network, r->r6.plen), - sizeof(n)) - == 0)); + || r->r4.network == nm_ip4_addr_clear_host_address(r->r4.network, r->r4.plen)); + nm_assert(IS_IPv4 + || (memcmp(&r->r6.network, + nm_ip6_addr_clear_host_address(&n, &r->r6.network, r->r6.plen), + sizeof(n)) + == 0)); if (r->rx.type_coerced != nm_platform_route_type_coerce(RTN_UNICAST)) continue; @@ -1602,7 +1603,7 @@ nm_utils_ip_routes_to_dbus(int addr_family, &route_builder, "{sv}", "dest", - g_variant_new_string(nm_utils_inet_ntop(addr_family, r->rx.network_ptr, addr_str))); + g_variant_new_string(nm_inet_ntop(addr_family, r->rx.network_ptr, addr_str))); g_variant_builder_add(&route_builder, "{sv}", @@ -1615,7 +1616,7 @@ nm_utils_ip_routes_to_dbus(int addr_family, &route_builder, "{sv}", "next-hop", - g_variant_new_string(nm_utils_inet_ntop(addr_family, gateway, addr_str))); + g_variant_new_string(nm_inet_ntop(addr_family, gateway, addr_str))); } g_variant_builder_add(&route_builder, @@ -1680,7 +1681,7 @@ nm_utils_platform_capture_ip_setting(NMPlatform *platform, NMDedupMultiIter iter; const NMPObject *obj; const char *method = NULL; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; const NMPlatformIPXRoute *best_default_route = NULL; s_ip = @@ -1782,13 +1783,13 @@ nm_utils_platform_capture_ip_setting(NMPlatform *platform, } if (best_default_route && nm_setting_ip_config_get_num_addresses(s_ip) > 0) { - g_object_set(s_ip, - NM_SETTING_IP_CONFIG_GATEWAY, - nm_utils_inet_ntop( - addr_family, + g_object_set( + s_ip, + NM_SETTING_IP_CONFIG_GATEWAY, + nm_inet_ntop(addr_family, nm_platform_ip_route_get_gateway(addr_family, &best_default_route->rx), sbuf), - NULL); + NULL); } return NM_SETTING(g_steal_pointer(&s_ip)); @@ -1839,7 +1840,7 @@ nm_platform_setup(NMPlatform *instance) * Returns: (transfer none): The #NMPlatform singleton reference. */ NMPlatform * -nm_platform_get() +nm_platform_get(void) { g_assert(singleton_instance); @@ -1851,11 +1852,11 @@ nm_platform_get() void nm_linux_platform_setup(void) { - nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, FALSE)); + nm_platform_setup(nm_linux_platform_new(NULL, FALSE, FALSE, FALSE)); } void nm_linux_platform_setup_with_tc_cache(void) { - nm_platform_setup(nm_linux_platform_new(FALSE, FALSE, TRUE)); + nm_platform_setup(nm_linux_platform_new(NULL, FALSE, FALSE, TRUE)); } diff --git a/src/core/devices/adsl/nm-atm-manager.c b/src/core/devices/adsl/nm-atm-manager.c index cc8d37e6..f3c0d367 100644 --- a/src/core/devices/adsl/nm-atm-manager.c +++ b/src/core/devices/adsl/nm-atm-manager.c @@ -17,7 +17,8 @@ /*****************************************************************************/ #define NM_TYPE_ATM_MANAGER (nm_atm_manager_get_type()) -#define NM_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) +#define NM_ATM_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) #define NM_ATM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) #define NM_IS_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_ATM_MANAGER)) diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index 79705c28..fcd16b1c 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -214,12 +214,12 @@ error: } static void -link_changed_cb(NMPlatform *platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDeviceAdsl *self) +link_changed_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + const NMPlatformLink *info, + int change_type_i, + NMDeviceAdsl *self) { const NMPlatformSignalChangeType change_type = change_type_i; diff --git a/src/core/devices/adsl/nm-device-adsl.h b/src/core/devices/adsl/nm-device-adsl.h index c5c18901..287a1401 100644 --- a/src/core/devices/adsl/nm-device-adsl.h +++ b/src/core/devices/adsl/nm-device-adsl.h @@ -10,7 +10,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_ADSL (nm_device_adsl_get_type()) -#define NM_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) +#define NM_DEVICE_ADSL(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) #define NM_DEVICE_ADSL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) #define NM_IS_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ADSL)) diff --git a/src/core/devices/bluetooth/nm-bluez-manager.c b/src/core/devices/bluetooth/nm-bluez-manager.c index 6bc00faf..ac26ede8 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.c +++ b/src/core/devices/bluetooth/nm-bluez-manager.c @@ -1010,8 +1010,9 @@ _network_server_get_bluez_manager(const NMBtVTableNetworkServer *vtable_network_ { NMBluezManager *self; - self = (NMBluezManager *) (((char *) vtable_network_server) - - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server)); + self = NM_CAST_ALIGN(NMBluezManager, + (((char *) vtable_network_server) + - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server))); g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), NULL); diff --git a/src/core/devices/bluetooth/nm-bluez-manager.h b/src/core/devices/bluetooth/nm-bluez-manager.h index 299f5c3b..7c823c64 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.h +++ b/src/core/devices/bluetooth/nm-bluez-manager.h @@ -8,7 +8,7 @@ #define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type()) #define NM_BLUEZ_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) #define NM_BLUEZ_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) #define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_BLUEZ_MANAGER)) diff --git a/src/core/devices/bluetooth/nm-device-bt.h b/src/core/devices/bluetooth/nm-device-bt.h index 59457fba..bf17e91f 100644 --- a/src/core/devices/bluetooth/nm-device-bt.h +++ b/src/core/devices/bluetooth/nm-device-bt.h @@ -9,7 +9,7 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_BT (nm_device_bt_get_type()) -#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) +#define NM_DEVICE_BT(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) #define NM_DEVICE_BT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) #define NM_IS_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BT)) diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index d6543356..870a1c14 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -21,7 +21,6 @@ /*****************************************************************************/ typedef struct { - gulong parent_state_id; } NMDevice6LowpanPrivate; struct _NMDevice6Lowpan { @@ -41,51 +40,15 @@ G_DEFINE_TYPE(NMDevice6Lowpan, nm_device_6lowpan, NM_TYPE_DEVICE) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(user_data); - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_changed_notify(NMDevice *device, int old_ifindex, NMDevice *old_parent, int new_ifindex, NMDevice *new_parent) { - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(device); - NMDevice6LowpanPrivate *priv = NM_DEVICE_6LOWPAN_GET_PRIVATE(self); - NM_DEVICE_CLASS(nm_device_6lowpan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - if (new_ifindex > 0) { /* Recheck availability now that the parent has changed */ nm_device_queue_recheck_available(device, @@ -272,7 +235,7 @@ nm_device_6lowpan_class_init(NMDevice6LowpanClass *klass) #define NM_TYPE_6LOWPAN_DEVICE_FACTORY (nm_6lowpan_device_factory_get_type()) #define NM_6LOWPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-6lowpan.h b/src/core/devices/nm-device-6lowpan.h index 34ea3c8d..bc6f77c4 100644 --- a/src/core/devices/nm-device-6lowpan.h +++ b/src/core/devices/nm-device-6lowpan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_6LOWPAN (nm_device_6lowpan_get_type()) #define NM_DEVICE_6LOWPAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) #define NM_DEVICE_6LOWPAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) #define NM_IS_DEVICE_6LOWPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_6LOWPAN)) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 10765b60..0b0697e3 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -20,6 +20,7 @@ #include "libnm-core-intern/nm-core-internal.h" #include "nm-manager.h" #include "nm-setting-bond-port.h" +#include "nm-bond-manager.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond #include "nm-device-logging.h" @@ -59,7 +60,8 @@ /*****************************************************************************/ struct _NMDeviceBond { - NMDevice parent; + NMDevice parent; + NMBondManager *bond_manager; }; struct _NMDeviceBondClass { @@ -178,7 +180,9 @@ update_connection(NMDevice *device, NMConnection *connection) gs_free char *value = NULL; char *p; - if (NM_IN_STRSET(option, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE)) + if (NM_IN_STRSET(option, + NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, + NM_SETTING_BOND_OPTION_BALANCE_SLB)) continue; value = @@ -224,9 +228,10 @@ controller_update_port_connection(NMDevice *self, GError **error) { NMSettingBondPort *s_port; - int ifindex_port = nm_device_get_ifindex(port); - uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; - gs_free char *queue_id_str = NULL; + int ifindex_port = nm_device_get_ifindex(port); + NMConnection *applied_connection = nm_device_get_applied_connection(self); + uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; + gs_free char *queue_id_str = NULL; g_return_val_if_fail(ifindex_port > 0, FALSE); @@ -243,7 +248,7 @@ controller_update_port_connection(NMDevice *self, g_object_set(nm_connection_get_setting_connection(connection), NM_SETTING_CONNECTION_MASTER, - nm_device_get_iface(self), + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, NULL); @@ -274,10 +279,10 @@ set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new in_addr_t a4; s = new_strv[i]; - if (nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &a4)) { + if (nm_inet_parse_bin(AF_INET, s, NULL, &a4)) { char sbuf[INET_ADDRSTRLEN]; - _nm_utils_inet4_ntop(a4, sbuf); + nm_inet4_ntop(a4, sbuf); if (!nm_streq(s, sbuf)) { if (!free_list) free_list = g_ptr_array_new_with_free_func(g_free); @@ -368,7 +373,7 @@ _bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_ for (i = 0; ip[i]; i++) { if (added > NM_BOND_MAX_ARP_TARGETS - 1) break; - if (!nm_utils_parse_inaddr_bin(AF_INET, ip[i], NULL, &in_a)) + if (!nm_inet_parse_bin(AF_INET, ip[i], NULL, &in_a)) nm_assert_not_reached(); /* verify() already validated the IP addresses */ out[added++] = in_a; @@ -460,10 +465,97 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); } +static void +_balance_slb_cb(NMBondManager *bond_manager, NMBondManagerEventType event_type, gpointer user_data) +{ + NMDevice *device = user_data; + NMDeviceBond *self = NM_DEVICE_BOND(device); + + nm_assert(NM_IS_DEVICE_BOND(self)); + nm_assert(self->bond_manager == bond_manager); + + switch (event_type) { + case NM_BOND_MANAGER_EVENT_TYPE_STATE: + switch (nm_bond_manager_get_state(bond_manager)) { + case NM_OPTION_BOOL_FALSE: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED) { + _LOGD(LOGD_BOND, "balance-slb: failed"); + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } + return; + case NM_OPTION_BOOL_TRUE: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED + && nm_device_devip_get_state(device, AF_UNSPEC) <= NM_DEVICE_IP_STATE_PENDING) { + nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_READY, NULL); + } + return; + case NM_OPTION_BOOL_DEFAULT: + if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED + && nm_device_devip_get_state(device, AF_UNSPEC) == NM_DEVICE_IP_STATE_READY) { + /* We are again busy. We can also go back to "pending" from "ready". + * If ip-config state is not yet complete, this will further delay it. + * Otherwise, it should have no effect. */ + nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL); + } + return; + } + nm_assert_not_reached(); + return; + } + + nm_assert_not_reached(); +} + +static void +_balance_slb_setup(NMDeviceBond *self, NMConnection *connection) +{ + int ifindex = nm_device_get_ifindex(NM_DEVICE(self)); + gboolean balance_slb = FALSE; + const char *uuid; + NMSettingBond *s_bond; + + if (ifindex > 0 && connection && (s_bond = nm_connection_get_setting_bond(connection))) + balance_slb = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_BALANCE_SLB); + + if (!balance_slb) { + if (nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy)) { + _LOGD(LOGD_BOND, "balance-slb: stopped"); + nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_NONE, NULL); + } + return; + } + + uuid = nm_connection_get_uuid(connection); + + if (self->bond_manager) { + if (nm_bond_manager_get_ifindex(self->bond_manager) == ifindex + && nm_streq0(nm_bond_manager_get_connection_uuid(self->bond_manager), uuid)) { + _LOGD(LOGD_BOND, "balance-slb: reapply"); + nm_bond_manager_reapply(self->bond_manager); + return; + } + nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy); + _LOGD(LOGD_BOND, "balance-slb: restart"); + } + + _LOGD(LOGD_BOND, "balance-slb: start"); + if (nm_device_devip_get_state(NM_DEVICE(self), AF_UNSPEC) < NM_DEVICE_IP_STATE_PENDING) + nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL); + self->bond_manager = nm_bond_manager_new(nm_device_get_platform(NM_DEVICE(self)), + ifindex, + uuid, + _balance_slb_cb, + self); + nm_assert(nm_bond_manager_get_state(self->bond_manager) == NM_OPTION_BOOL_DEFAULT); +} + static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMDeviceBond *self = NM_DEVICE_BOND(device); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMConnection *connection; NMSettingBond *s_bond; NMPlatformLnkBond props; @@ -476,6 +568,14 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) s_bond = nm_connection_get_setting_bond(connection); g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE); + if (nm_device_sys_iface_state_is_external(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + + _balance_slb_setup(self, connection); + + if (nm_device_sys_iface_state_is_external_or_assume(device)) + return NM_ACT_STAGE_RETURN_SUCCESS; + _platform_lnk_bond_init_from_setting(s_bond, &props); /* Interface must be down to set bond options */ @@ -684,7 +784,7 @@ can_reapply_change(NMDevice *device, const char *name = *option_list; /* We support changes to these */ - if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL)) + if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL, NM_SETTING_BOND_OPTION_BALANCE_SLB)) continue; /* Reject any other changes */ @@ -730,6 +830,16 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne set_bond_arp_ip_targets(device, s_bond); set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_REAPPLY_SUBSET)); + + _balance_slb_setup(self, con_new); +} + +static void +deactivate(NMDevice *device) +{ + NMDeviceBond *self = NM_DEVICE_BOND(device); + + _balance_slb_setup(self, NULL); } /*****************************************************************************/ @@ -768,20 +878,22 @@ nm_device_bond_class_init(NMDeviceBondClass *klass) device_class->update_connection = update_connection; device_class->master_update_slave_connection = controller_update_port_connection; - device_class->create_and_realize = create_and_realize; - device_class->act_stage1_prepare = act_stage1_prepare; + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; device_class->attach_port = attach_port; device_class->detach_port = detach_port; device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; + device_class->deactivate = deactivate; } /*****************************************************************************/ #define NM_TYPE_BOND_DEVICE_FACTORY (nm_bond_device_factory_get_type()) #define NM_BOND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-bond.h b/src/core/devices/nm-device-bond.h index 19301793..083189bb 100644 --- a/src/core/devices/nm-device-bond.h +++ b/src/core/devices/nm-device-bond.h @@ -9,7 +9,8 @@ #include "nm-device.h" #define NM_TYPE_DEVICE_BOND (nm_device_bond_get_type()) -#define NM_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond)) +#define NM_DEVICE_BOND(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond)) #define NM_DEVICE_BOND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BOND, NMDeviceBondClass)) #define NM_IS_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BOND)) diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index 31cf361e..c5ce34c2 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -679,9 +679,10 @@ master_update_slave_connection(NMDevice *device, NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); NMSettingConnection *s_con; NMSettingBridgePort *s_port; - int ifindex_slave = nm_device_get_ifindex(slave); - const char *iface = nm_device_get_iface(device); - const Option *option; + int ifindex_slave = nm_device_get_ifindex(slave); + NMConnection *applied_connection = nm_device_get_applied_connection(device); + + const Option *option; g_return_val_if_fail(ifindex_slave > 0, FALSE); @@ -717,7 +718,7 @@ master_update_slave_connection(NMDevice *device, g_object_set(s_con, NM_SETTING_CONNECTION_MASTER, - iface, + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); @@ -1270,7 +1271,7 @@ nm_device_bridge_class_init(NMDeviceBridgeClass *klass) #define NM_TYPE_BRIDGE_DEVICE_FACTORY (nm_bridge_device_factory_get_type()) #define NM_BRIDGE_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-bridge.h b/src/core/devices/nm-device-bridge.h index 32437947..6d9f1614 100644 --- a/src/core/devices/nm-device-bridge.h +++ b/src/core/devices/nm-device-bridge.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_BRIDGE (nm_device_bridge_get_type()) #define NM_DEVICE_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridge)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridge)) #define NM_DEVICE_BRIDGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridgeClass)) #define NM_IS_DEVICE_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BRIDGE)) diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index de701a0d..36a0ee6f 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -136,7 +136,7 @@ nm_device_dummy_class_init(NMDeviceDummyClass *klass) #define NM_TYPE_DUMMY_DEVICE_FACTORY (nm_dummy_device_factory_get_type()) #define NM_DUMMY_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-dummy.h b/src/core/devices/nm-device-dummy.h index 2845b4eb..9e550887 100644 --- a/src/core/devices/nm-device-dummy.h +++ b/src/core/devices/nm-device-dummy.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_DUMMY (nm_device_dummy_get_type()) #define NM_DEVICE_DUMMY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) #define NM_DEVICE_DUMMY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) #define NM_IS_DEVICE_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_DUMMY)) diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 4788cdc6..97cf84a1 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1735,11 +1735,10 @@ new_default_connection(NMDevice *self) /* Create a stable UUID. The UUID is also the Network_ID for stable-privacy addr-gen-mode, * thus when it changes we will also generate different IPv6 addresses. */ - uuid = nm_uuid_generate_from_strings("default-wired", - nm_utils_machine_id_str(), - defname, - perm_hw_addr ?: iface, - NULL); + uuid = nm_uuid_generate_from_strings_old("default-wired", + nm_utils_machine_id_str(), + defname, + perm_hw_addr ?: iface); g_object_set(setting, NM_SETTING_CONNECTION_ID, @@ -2114,8 +2113,10 @@ nm_device_ethernet_class_init(NMDeviceEthernetClass *klass) /*****************************************************************************/ #define NM_TYPE_ETHERNET_DEVICE_FACTORY (nm_ethernet_device_factory_get_type()) -#define NM_ETHERNET_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ETHERNET_DEVICE_FACTORY, NMEthernetDeviceFactory)) +#define NM_ETHERNET_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_ETHERNET_DEVICE_FACTORY, \ + NMEthernetDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-ethernet.h b/src/core/devices/nm-device-ethernet.h index 6e134d71..6c4acb82 100644 --- a/src/core/devices/nm-device-ethernet.h +++ b/src/core/devices/nm-device-ethernet.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_ETHERNET (nm_device_ethernet_get_type()) #define NM_DEVICE_ETHERNET(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) #define NM_DEVICE_ETHERNET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_IS_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ETHERNET)) diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 41e9480f..2f0ae2e8 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -398,6 +398,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_ethernet_device_factory_get_type); _ADD_INTERNAL(nm_infiniband_device_factory_get_type); _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); + _ADD_INTERNAL(nm_loopback_device_factory_get_type); _ADD_INTERNAL(nm_macsec_device_factory_get_type); _ADD_INTERNAL(nm_macvlan_device_factory_get_type); _ADD_INTERNAL(nm_ppp_device_factory_get_type); diff --git a/src/core/devices/nm-device-factory.h b/src/core/devices/nm-device-factory.h index 51d64767..ac5ae05f 100644 --- a/src/core/devices/nm-device-factory.h +++ b/src/core/devices/nm-device-factory.h @@ -17,7 +17,7 @@ #define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type()) #define NM_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) #define NM_DEVICE_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryClass)) #define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_FACTORY)) @@ -208,7 +208,8 @@ NMDevice *nm_device_factory_create_device(NMDeviceFactory *factory, \ NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ - static void nm_##lower##_device_factory_init(NM##mixed##DeviceFactory *self) {} \ + static void nm_##lower##_device_factory_init(NM##mixed##DeviceFactory *self) \ + {} \ \ static void nm_##lower##_device_factory_class_init(NM##mixed##DeviceFactoryClass *klass) \ { \ diff --git a/src/core/devices/nm-device-generic.h b/src/core/devices/nm-device-generic.h index 48c43523..f06a5bdc 100644 --- a/src/core/devices/nm-device-generic.h +++ b/src/core/devices/nm-device-generic.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_GENERIC (nm_device_generic_get_type()) #define NM_DEVICE_GENERIC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric)) #define NM_DEVICE_GENERIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass)) #define NM_IS_DEVICE_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_GENERIC)) diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index 6b6aef86..d025931e 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -403,10 +403,10 @@ nm_device_infiniband_class_init(NMDeviceInfinibandClass *klass) /*****************************************************************************/ #define NM_TYPE_INFINIBAND_DEVICE_FACTORY (nm_infiniband_device_factory_get_type()) -#define NM_INFINIBAND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - NM_TYPE_INFINIBAND_DEVICE_FACTORY, \ - NMInfinibandDeviceFactory)) +#define NM_INFINIBAND_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_INFINIBAND_DEVICE_FACTORY, \ + NMInfinibandDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-infiniband.h b/src/core/devices/nm-device-infiniband.h index 69994a2d..5c915dd4 100644 --- a/src/core/devices/nm-device-infiniband.h +++ b/src/core/devices/nm-device-infiniband.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_INFINIBAND (nm_device_infiniband_get_type()) #define NM_DEVICE_INFINIBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) #define NM_DEVICE_INFINIBAND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) #define NM_IS_DEVICE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_INFINIBAND)) diff --git a/src/core/devices/nm-device-ip-tunnel.c b/src/core/devices/nm-device-ip-tunnel.c index 02680dd7..a5760bf4 100644 --- a/src/core/devices/nm-device-ip-tunnel.c +++ b/src/core/devices/nm-device-ip-tunnel.c @@ -39,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIPTunnel, PROP_OUTPUT_KEY, PROP_ENCAPSULATION_LIMIT, PROP_FLOW_LABEL, + PROP_FWMARK, PROP_FLAGS, ); typedef struct { @@ -53,6 +54,7 @@ typedef struct { char *output_key; guint8 encap_limit; guint32 flow_label; + guint32 fwmark; NMIPTunnelFlags flags; } NMDeviceIPTunnelPrivate; @@ -107,12 +109,12 @@ address_equal_pp(int addr_family, const char *a, const char *b) nm_assert_addr_family(addr_family); if (a) { - if (!nm_utils_parse_inaddr_bin(addr_family, a, NULL, &addr_a_val)) + if (!nm_inet_parse_bin(addr_family, a, NULL, &addr_a_val)) nm_assert_not_reached(); addr_a = &addr_a_val; } if (b) { - if (!nm_utils_parse_inaddr_bin(addr_family, b, NULL, &addr_b_val)) + if (!nm_inet_parse_bin(addr_family, b, NULL, &addr_b_val)) nm_assert_not_reached(); addr_b = &addr_b_val; } @@ -125,7 +127,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) { nm_assert_addr_family(addr_family); nm_assert(p_addr); - nm_assert(!*p_addr || nm_utils_ipaddr_is_normalized(addr_family, *p_addr)); + nm_assert(!*p_addr || nm_inet_is_normalized(addr_family, *p_addr)); if (!addr_new || nm_ip_addr_is_null(addr_family, addr_new)) { if (nm_clear_g_free(p_addr)) @@ -136,7 +138,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) if (*p_addr) { NMIPAddr addr_val; - if (!nm_utils_parse_inaddr_bin(addr_family, *p_addr, NULL, &addr_val)) + if (!nm_inet_parse_bin(addr_family, *p_addr, NULL, &addr_val)) nm_assert_not_reached(); if (nm_ip_addr_equal(addr_family, &addr_val, addr_new)) @@ -145,7 +147,7 @@ address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) g_free(*p_addr); } - *p_addr = nm_utils_inet_ntop_dup(addr_family, addr_new); + *p_addr = nm_inet_ntop_dup(addr_family, addr_new); return TRUE; } @@ -162,8 +164,10 @@ update_properties_from_ifindex(NMDevice *device, int ifindex) guint8 encap_limit = 0; gboolean pmtud = FALSE; guint32 flow_label = 0; + guint32 fwmark = 0; NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE; - char *key; + gs_free char *input_key = NULL; + gs_free char *output_key = NULL; if (ifindex <= 0) { clear: @@ -207,35 +211,10 @@ clear: tos = lnk->tos; pmtud = lnk->path_mtu_discovery; - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } - - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } + if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) + input_key = g_strdup_printf("%u", lnk->input_key); + if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) + output_key = g_strdup_printf("%u", lnk->output_key); } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { const NMPlatformLnkSit *lnk; @@ -296,36 +275,45 @@ clear: flags = ip6tnl_flags_plat_to_setting(lnk->flags); if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_IP6GRE, NM_IP_TUNNEL_MODE_IP6GRETAP)) { - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } + if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) + input_key = g_strdup_printf("%u", lnk->input_key); + if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) + output_key = g_strdup_printf("%u", lnk->output_key); + } + } else if (priv->mode == NM_IP_TUNNEL_MODE_VTI) { + const NMPlatformLnkVti *lnk; - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } + lnk = nm_platform_link_get_lnk_vti(nm_device_get_platform(device), ifindex, NULL); + if (!lnk) { + _LOGW(LOGD_PLATFORM, "could not read %s properties", "vti"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local.addr4 = lnk->local; + remote.addr4 = lnk->remote; + fwmark = lnk->fwmark; + if (lnk->ikey) + input_key = g_strdup_printf("%u", lnk->ikey); + if (lnk->okey) + output_key = g_strdup_printf("%u", lnk->okey); + } else if (priv->mode == NM_IP_TUNNEL_MODE_VTI6) { + const NMPlatformLnkVti6 *lnk; + + lnk = nm_platform_link_get_lnk_vti6(nm_device_get_platform(device), ifindex, NULL); + if (!lnk) { + _LOGW(LOGD_PLATFORM, "could not read %s properties", "vti6"); + goto clear; } + + parent_ifindex = lnk->parent_ifindex; + local.addr6 = lnk->local; + remote.addr6 = lnk->remote; + fwmark = lnk->fwmark; + if (lnk->ikey) + input_key = g_strdup_printf("%u", lnk->ikey); + if (lnk->okey) + output_key = g_strdup_printf("%u", lnk->okey); } else g_return_if_reached(); @@ -337,7 +325,6 @@ clear: _notify(self, PROP_REMOTE); out: - if (priv->ttl != ttl) { priv->ttl = ttl; _notify(self, PROP_TTL); @@ -363,6 +350,23 @@ out: _notify(self, PROP_FLOW_LABEL); } + if (!nm_streq0(priv->input_key, input_key)) { + g_free(priv->input_key); + priv->input_key = g_steal_pointer(&input_key); + _notify(self, PROP_INPUT_KEY); + } + + if (!nm_streq0(priv->output_key, output_key)) { + g_free(priv->output_key); + priv->output_key = g_steal_pointer(&output_key); + _notify(self, PROP_OUTPUT_KEY); + } + + if (priv->fwmark != fwmark) { + priv->fwmark = fwmark; + _notify(self, PROP_FWMARK); + } + if (priv->flags != flags) { priv->flags = flags; _notify(self, PROP_FLAGS); @@ -467,11 +471,17 @@ update_connection(NMDevice *device, NMConnection *connection) NULL); } + if (nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel) != priv->fwmark) { + g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_FWMARK, priv->fwmark, NULL); + } + if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_GRE, NM_IP_TUNNEL_MODE_GRETAP, NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) { + NM_IP_TUNNEL_MODE_IP6GRETAP, + NM_IP_TUNNEL_MODE_VTI, + NM_IP_TUNNEL_MODE_VTI6)) { if (g_strcmp0(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), priv->input_key)) { g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_INPUT_KEY, @@ -493,6 +503,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL(device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); NMSettingIPTunnel *s_ip_tunnel; + NMIPTunnelMode mode; const char *parent; if (!NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class) @@ -500,8 +511,9 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * return FALSE; s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); + mode = nm_setting_ip_tunnel_get_mode(s_ip_tunnel); - if (nm_setting_ip_tunnel_get_mode(s_ip_tunnel) != priv->mode) { + if (mode != priv->mode) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "incompatible IP tunnel mode"); @@ -536,14 +548,16 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * return FALSE; } - if (nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) { + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "TTL of IP tunnel mismatches"); return FALSE; } - if (nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) { + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "TOS of IP tunnel mismatches"); @@ -551,11 +565,14 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * } if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) - != priv->path_mtu_discovery) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MTU discovery setting of IP tunnel mismatches"); + if (!NM_IN_SET(mode, NM_IP_TUNNEL_MODE_VTI, NM_IP_TUNNEL_MODE_VTI6) + && nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) + != priv->path_mtu_discovery) { + nm_utils_error_set(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MTU discovery setting of IP tunnel mismatches: %d vs %d", + nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel), + priv->path_mtu_discovery); return FALSE; } } else { @@ -605,6 +622,10 @@ platform_link_to_tunnel_mode(const NMPlatformLink *link) return NM_IP_TUNNEL_MODE_IPIP; case NM_LINK_TYPE_SIT: return NM_IP_TUNNEL_MODE_SIT; + case NM_LINK_TYPE_VTI: + return NM_IP_TUNNEL_MODE_VTI; + case NM_LINK_TYPE_VTI6: + return NM_IP_TUNNEL_MODE_VTI6; default: g_return_val_if_reached(NM_IP_TUNNEL_MODE_UNKNOWN); } @@ -630,7 +651,9 @@ tunnel_mode_to_link_type(NMIPTunnelMode tunnel_mode) case NM_IP_TUNNEL_MODE_SIT: return NM_LINK_TYPE_SIT; case NM_IP_TUNNEL_MODE_VTI: + return NM_LINK_TYPE_VTI; case NM_IP_TUNNEL_MODE_VTI6: + return NM_LINK_TYPE_VTI6; case NM_IP_TUNNEL_MODE_ISATAP: return NM_LINK_TYPE_UNKNOWN; case NM_IP_TUNNEL_MODE_UNKNOWN: @@ -654,6 +677,8 @@ create_and_realize(NMDevice *device, NMPlatformLnkSit lnk_sit = {}; NMPlatformLnkIpIp lnk_ipip = {}; NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; + NMPlatformLnkVti lnk_vti = {}; + NMPlatformLnkVti6 lnk_vti6 = {}; const char *str; gint64 val; NMIPTunnelMode mode; @@ -871,6 +896,81 @@ create_and_realize(NMDevice *device, return FALSE; } break; + case NM_IP_TUNNEL_MODE_VTI: + if (parent) + lnk_vti.parent_ifindex = nm_device_get_ifindex(parent); + + str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); + if (str) + inet_pton(AF_INET, str, &lnk_vti.local); + + str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); + nm_assert(str); + inet_pton(AF_INET, str, &lnk_vti.remote); + + lnk_vti.ikey = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti.okey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti.fwmark = nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel); + + r = nm_platform_link_vti_add(nm_device_get_platform(device), iface, &lnk_vti, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VTI interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_VTI6: + if (parent) + lnk_vti6.parent_ifindex = nm_device_get_ifindex(parent); + + str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); + if (str) + inet_pton(AF_INET6, str, &lnk_vti6.local); + + str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); + nm_assert(str); + inet_pton(AF_INET6, str, &lnk_vti6.remote); + + lnk_vti6.ikey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti6.okey = + _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + 0); + lnk_vti6.fwmark = nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel); + + r = nm_platform_link_vti6_add(nm_device_get_platform(device), iface, &lnk_vti6, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VTI6 interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + break; default: g_set_error(error, NM_DEVICE_ERROR, @@ -986,6 +1086,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_FLAGS: g_value_set_uint(value, priv->flags); break; + case PROP_FWMARK: + g_value_set_uint(value, priv->fwmark); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1021,7 +1124,8 @@ constructed(GObject *object) NM_IP_TUNNEL_MODE_IPIP6, NM_IP_TUNNEL_MODE_IP6IP6, NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) + NM_IP_TUNNEL_MODE_IP6GRETAP, + NM_IP_TUNNEL_MODE_VTI6)) priv->addr_family = AF_INET6; else priv->addr_family = AF_INET; @@ -1070,6 +1174,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FlowLabel", "u", NM_DEVICE_IP_TUNNEL_FLOW_LABEL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FwMark", + "u", + NM_DEVICE_IP_TUNNEL_FWMARK), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_DEVICE_IP_TUNNEL_FLAGS), ), ), @@ -1097,7 +1204,9 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass) NM_LINK_TYPE_IP6GRE, NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_SIT); + NM_LINK_TYPE_SIT, + NM_LINK_TYPE_VTI, + NM_LINK_TYPE_VTI6); device_class->act_stage1_prepare = act_stage1_prepare; device_class->link_changed = link_changed; @@ -1192,14 +1301,24 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass) 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_FWMARK] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FWMARK, + "", + "", + 0, + G_MAXUINT32, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); } /*****************************************************************************/ #define NM_TYPE_IP_TUNNEL_DEVICE_FACTORY (nm_ip_tunnel_device_factory_get_type()) -#define NM_IP_TUNNEL_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_TUNNEL_DEVICE_FACTORY, NMIPTunnelDeviceFactory)) +#define NM_IP_TUNNEL_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_IP_TUNNEL_DEVICE_FACTORY, \ + NMIPTunnelDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, @@ -1282,7 +1401,9 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_LINK_TYPE_IPIP, NM_LINK_TYPE_IP6TNL, NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP) + NM_LINK_TYPE_IP6GRETAP, + NM_LINK_TYPE_VTI, + NM_LINK_TYPE_VTI6) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME), factory_class->create_device = create_device; factory_class->get_connection_parent = get_connection_parent; diff --git a/src/core/devices/nm-device-ip-tunnel.h b/src/core/devices/nm-device-ip-tunnel.h index 0a941cc2..1d7b7381 100644 --- a/src/core/devices/nm-device-ip-tunnel.h +++ b/src/core/devices/nm-device-ip-tunnel.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type()) #define NM_DEVICE_IP_TUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) #define NM_DEVICE_IP_TUNNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) #define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IP_TUNNEL)) @@ -31,6 +31,7 @@ #define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" #define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" #define NM_DEVICE_IP_TUNNEL_FLAGS "flags" +#define NM_DEVICE_IP_TUNNEL_FWMARK "fwmark" typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass; diff --git a/src/core/devices/nm-device-logging.h b/src/core/devices/nm-device-logging.h index c2602189..ffc90c2d 100644 --- a/src/core/devices/nm-device-logging.h +++ b/src/core/devices/nm-device-logging.h @@ -11,15 +11,12 @@ #if !_NM_CC_SUPPORT_GENERIC #define _NM_DEVICE_CAST(self) ((NMDevice *) (self)) #elif !defined(_NMLOG_DEVICE_TYPE) -#define _NM_DEVICE_CAST(self) \ - _Generic((self), NMDevice * : ((NMDevice *) (self)), NMDevice *const : ((NMDevice *) (self))) +#define _NM_DEVICE_CAST(self) _Generic((self), NMDevice * : ((NMDevice *) (self))) #else -#define _NM_DEVICE_CAST(self) \ - _Generic((self), \ - _NMLOG_DEVICE_TYPE * : ((NMDevice *) (self)), \ - _NMLOG_DEVICE_TYPE * const: ((NMDevice *) (self)), \ - NMDevice * : ((NMDevice *) (self)), \ - NMDevice * const: ((NMDevice *) (self))) +#define _NM_DEVICE_CAST(self) \ + _Generic((self), _NMLOG_DEVICE_TYPE * \ + : ((NMDevice *) (self)), NMDevice * \ + : ((NMDevice *) (self))) #endif #undef _NMLOG_ENABLED diff --git a/src/core/devices/nm-device-loopback.c b/src/core/devices/nm-device-loopback.c new file mode 100644 index 00000000..ec72aa96 --- /dev/null +++ b/src/core/devices/nm-device-loopback.c @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" +#include "nm-device-loopback.h" +#include "nm-device-private.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-loopback.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceLoopback +#include "nm-device-logging.h" + +/*****************************************************************************/ + +struct _NMDeviceLoopback { + NMDevice parent; +}; + +struct _NMDeviceLoopbackClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceLoopback, nm_device_loopback, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *dev) +{ + /* In many aspects, loopback is a software device. Still, don't return + * NM_DEVICE_CAP_IS_SOFTWARE here, because we cannot delete nor create + * such an interface. */ + return NM_DEVICE_CAP_NONE; +} + +static guint32 +get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) +{ + return nm_device_get_configured_mtu_from_connection(device, + NM_TYPE_SETTING_LOOPBACK, + out_source); +} + +static const char * +get_auto_ip_config_method(NMDevice *device, int addr_family) +{ + return NM_IS_IPv4(addr_family) ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL + : NM_SETTING_IP6_CONFIG_METHOD_MANUAL; +} + +static gboolean +complete_connection(NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const *existing_connections, + GError **error) +{ + nm_utils_complete_generic_with_params(nm_device_get_platform(device), + connection, + NM_SETTING_LOOPBACK_SETTING_NAME, + existing_connections, + NULL, + _("Loopback connection"), + NULL, + nm_device_get_ip_iface(device)); + + _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK); + + return TRUE; +} + +static void +update_connection(NMDevice *device, NMConnection *connection) +{ + _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK); +} + +static gboolean +can_reapply_change(NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + if (!nm_streq(setting_name, NM_SETTING_LOOPBACK_SETTING_NAME)) { + return NM_DEVICE_CLASS(nm_device_loopback_parent_class) + ->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); + } + + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_LOOPBACK_SETTING_NAME, + error, + NM_SETTING_LOOPBACK_MTU); +} + +/*****************************************************************************/ + +static const NMDBusInterfaceInfoExtended interface_info_device_loopback = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(NM_DBUS_INTERFACE_DEVICE_LOOPBACK, ), +}; + +static void +nm_device_loopback_init(NMDeviceLoopback *self) +{} + +static void +nm_device_loopback_class_init(NMDeviceLoopbackClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_loopback); + + device_class->connection_type_supported = NM_SETTING_LOOPBACK_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_LOOPBACK_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK); + + device_class->complete_connection = complete_connection; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; + device_class->get_auto_ip_config_method = get_auto_ip_config_method; + device_class->get_configured_mtu = get_configured_mtu; + device_class->allow_autoconnect_on_external = TRUE; + device_class->can_reapply_change = can_reapply_change; +} + +/*****************************************************************************/ + +#define NM_TYPE_LOOPBACK_DEVICE_FACTORY (nm_loopback_device_factory_get_type()) +#define NM_LOOPBACK_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_LOOPBACK_DEVICE_FACTORY, \ + NMLoopbackDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new(NM_TYPE_DEVICE_LOOPBACK, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "Loopback", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_LOOPBACK, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_LOOPBACK, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + LOOPBACK, + Loopback, + loopback, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_LOOPBACK_SETTING_NAME), + factory_class->create_device = create_device;); diff --git a/src/core/devices/nm-device-loopback.h b/src/core/devices/nm-device-loopback.h new file mode 100644 index 00000000..fc62a94b --- /dev/null +++ b/src/core/devices/nm-device-loopback.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_LOOPBACK_H__ +#define __NETWORKMANAGER_DEVICE_LOOPBACK_H__ + +#include "nm-device-generic.h" + +#define NM_TYPE_DEVICE_LOOPBACK (nm_device_loopback_get_type()) +#define NM_DEVICE_LOOPBACK(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopback)) +#define NM_DEVICE_LOOPBACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass)) +#define NM_IS_DEVICE_LOOPBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_LOOPBACK)) +#define NM_IS_DEVICE_LOOPBACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_LOOPBACK)) +#define NM_DEVICE_LOOPBACK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass)) + +typedef struct _NMDeviceLoopback NMDeviceLoopback; +typedef struct _NMDeviceLoopbackClass NMDeviceLoopbackClass; + +GType nm_device_loopback_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_LOOPBACK_H__ */ diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 5b1f5fdc..130708bb 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -45,7 +45,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacsec, typedef struct { NMPlatformLnkMacsec props; - gulong parent_state_id; gulong parent_mtu_id; struct { @@ -92,25 +91,6 @@ static NM_UTILS_LOOKUP_STR_DEFINE(validation_mode_to_string, NM_UTILS_LOOKUP_STR_ITEM(2, "strict"), ); static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a MACsec device is limited by the parent's MTU. @@ -132,27 +112,13 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_macsec_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, + priv->parent_mtu_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_MTU, G_CALLBACK(parent_mtu_maybe_changed), device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } /* Recheck availability now that the parent has changed */ @@ -862,7 +828,6 @@ dispose(GObject *object) G_OBJECT_CLASS(nm_device_macsec_parent_class)->dispose(object); - nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_state_id == 0); nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_mtu_id == 0); } @@ -1011,7 +976,7 @@ nm_device_macsec_class_init(NMDeviceMacsecClass *klass) #define NM_TYPE_MACSEC_DEVICE_FACTORY (nm_macsec_device_factory_get_type()) #define NM_MACSEC_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACSEC_DEVICE_FACTORY, NMMacsecDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACSEC_DEVICE_FACTORY, NMMacsecDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-macsec.h b/src/core/devices/nm-device-macsec.h index e91fe51c..fefb773c 100644 --- a/src/core/devices/nm-device-macsec.h +++ b/src/core/devices/nm-device-macsec.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_MACSEC (nm_device_macsec_get_type()) #define NM_DEVICE_MACSEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsec)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsec)) #define NM_DEVICE_MACSEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsecClass)) #define NM_IS_DEVICE_MACSEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACSEC)) diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 40ecc5fd..3f57bfb1 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -29,7 +29,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacvlan, PROP_MODE, PROP_NO_PROMISC, PROP_TAP, ); typedef struct { - gulong parent_state_id; gulong parent_mtu_id; NMPlatformLnkMacvlan props; } NMDeviceMacvlanPrivate; @@ -103,25 +102,6 @@ platform_mode_to_string(guint mode) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacvlan *self = NM_DEVICE_MACVLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a macvlan/macvtap device is limited by the parent's MTU. @@ -143,27 +123,13 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_macvlan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, + priv->parent_mtu_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_MTU, G_CALLBACK(parent_mtu_maybe_changed), device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } if (new_ifindex > 0) { @@ -490,7 +456,6 @@ dispose(GObject *object) { G_OBJECT_CLASS(nm_device_macvlan_parent_class)->dispose(object); - nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_state_id == 0); nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_mtu_id == 0); } #endif @@ -566,7 +531,7 @@ nm_device_macvlan_class_init(NMDeviceMacvlanClass *klass) #define NM_TYPE_MACVLAN_DEVICE_FACTORY (nm_macvlan_device_factory_get_type()) #define NM_MACVLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACVLAN_DEVICE_FACTORY, NMMacvlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACVLAN_DEVICE_FACTORY, NMMacvlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-macvlan.h b/src/core/devices/nm-device-macvlan.h index 109a2bcd..86ac79c7 100644 --- a/src/core/devices/nm-device-macvlan.h +++ b/src/core/devices/nm-device-macvlan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_MACVLAN (nm_device_macvlan_get_type()) #define NM_DEVICE_MACVLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan)) #define NM_DEVICE_MACVLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass)) #define NM_IS_DEVICE_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACVLAN)) diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 6615b65e..1860df3c 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -337,7 +337,7 @@ nm_device_ppp_class_init(NMDevicePppClass *klass) #define NM_TYPE_PPP_DEVICE_FACTORY (nm_ppp_device_factory_get_type()) #define NM_PPP_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-ppp.h b/src/core/devices/nm-device-ppp.h index 24c119ab..0e8ca54a 100644 --- a/src/core/devices/nm-device-ppp.h +++ b/src/core/devices/nm-device-ppp.h @@ -7,7 +7,7 @@ #define __NETWORKMANAGER_DEVICE_PPP_H__ #define NM_TYPE_DEVICE_PPP (nm_device_ppp_get_type()) -#define NM_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_PPP, NMDevicePpp)) +#define NM_DEVICE_PPP(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_PPP, NMDevicePpp)) #define NM_DEVICE_PPP_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) #define NM_IS_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_PPP)) diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index e623e9c0..cbea7d7d 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -527,7 +527,7 @@ nm_device_tun_class_init(NMDeviceTunClass *klass) #define NM_TYPE_TUN_DEVICE_FACTORY (nm_tun_device_factory_get_type()) #define NM_TUN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TUN_DEVICE_FACTORY, NMTunDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TUN_DEVICE_FACTORY, NMTunDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-tun.h b/src/core/devices/nm-device-tun.h index 84497ea0..866d6c4f 100644 --- a/src/core/devices/nm-device-tun.h +++ b/src/core/devices/nm-device-tun.h @@ -9,7 +9,7 @@ #include "nm-device-generic.h" #define NM_TYPE_DEVICE_TUN (nm_device_tun_get_type()) -#define NM_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun)) +#define NM_DEVICE_TUN(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun)) #define NM_DEVICE_TUN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TUN, NMDeviceTunClass)) #define NM_IS_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TUN)) diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c index 170922eb..2bf24ae6 100644 --- a/src/core/devices/nm-device-utils.c +++ b/src/core/devices/nm-device-utils.c @@ -171,25 +171,25 @@ typedef struct { #define _NMLOG_PREFIX_NAME "resolve-addr" #define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG2(level, info, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ - ResolveAddrInfo *_info = (info); \ - char _addr_str[NM_UTILS_INET_ADDRSTRLEN]; \ - \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ - ",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_HASH_OBFUSCATE_PTR(_info), \ - nm_utils_inet_ntop(_info->addr_family, &_info->address, _addr_str) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG2(level, info, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + ResolveAddrInfo *_info = (info); \ + char _addr_str[NM_INET_ADDRSTRLEN]; \ + \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ + ",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(_info), \ + nm_inet_ntop(_info->addr_family, &_info->address, _addr_str) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END static void @@ -234,9 +234,9 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data static void resolve_addr_spawn_helper(ResolveAddrInfo *info) { - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; - nm_utils_inet_ntop(info->addr_family, &info->address, addr_str); + nm_inet_ntop(info->addr_family, &info->address, addr_str); _LOG2D(info, "start lookup via nm-daemon-helper"); nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str), g_task_get_cancellable(info->task), diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index 17115d33..c4b9e234 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -215,7 +215,7 @@ nm_device_veth_class_init(NMDeviceVethClass *klass) #define NM_TYPE_VETH_DEVICE_FACTORY (nm_veth_device_factory_get_type()) #define NM_VETH_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VETH_DEVICE_FACTORY, NMVethDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VETH_DEVICE_FACTORY, NMVethDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-veth.h b/src/core/devices/nm-device-veth.h index d43a0a4b..39182363 100644 --- a/src/core/devices/nm-device-veth.h +++ b/src/core/devices/nm-device-veth.h @@ -9,7 +9,8 @@ #include "nm-device-ethernet.h" #define NM_TYPE_DEVICE_VETH (nm_device_veth_get_type()) -#define NM_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VETH, NMDeviceVeth)) +#define NM_DEVICE_VETH(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VETH, NMDeviceVeth)) #define NM_DEVICE_VETH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VETH, NMDeviceVethClass)) #define NM_IS_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VETH)) diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 0c101c70..feb011db 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -8,6 +8,7 @@ #include "nm-device-vlan.h" #include <sys/socket.h> +#include <linux/if_ether.h> #include "nm-manager.h" #include "nm-utils.h" @@ -31,7 +32,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVlan, PROP_VLAN_ID, ); typedef struct { - gulong parent_state_id; gulong parent_hwaddr_id; gulong parent_mtu_id; guint vlan_id; @@ -54,25 +54,6 @@ G_DEFINE_TYPE(NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) /*****************************************************************************/ static void -parent_state_changed(NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) { /* the MTU of a VLAN device is limited by the parent's MTU. @@ -132,19 +113,10 @@ parent_changed_notify(NMDevice *device, NM_DEVICE_CLASS(nm_device_vlan_parent_class) ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); nm_clear_g_signal_handler(old_parent, &priv->parent_hwaddr_id); nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_hwaddr_id = g_signal_connect(new_parent, "notify::" NM_DEVICE_HW_ADDRESS, G_CALLBACK(parent_hwaddr_maybe_changed), @@ -156,12 +128,6 @@ parent_changed_notify(NMDevice *device, G_CALLBACK(parent_mtu_maybe_changed), device); parent_mtu_maybe_changed(new_parent, NULL, self); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } /* Recheck availability now that the parent has changed */ @@ -227,6 +193,8 @@ create_and_realize(NMDevice *device, int parent_ifindex; guint vlan_id; int r; + const char *protocol_str; + guint16 protocol = ETH_P_8021Q; s_vlan = nm_connection_get_setting_vlan(connection); g_assert(s_vlan); @@ -262,11 +230,22 @@ create_and_realize(NMDevice *device, vlan_id = nm_setting_vlan_get_id(s_vlan); + protocol_str = nm_setting_vlan_get_protocol(s_vlan); + if (protocol_str) { + if (nm_streq(protocol_str, "802.1ad")) + protocol = ETH_P_8021AD; + else + nm_assert(nm_streq(protocol_str, "802.1Q")); + } + r = nm_platform_link_vlan_add(nm_device_get_platform(device), iface, parent_ifindex, - vlan_id, - nm_setting_vlan_get_flags(s_vlan), + &((NMPlatformLnkVlan){ + .id = vlan_id, + .flags = nm_setting_vlan_get_flags(s_vlan), + .protocol = protocol, + }), out_plink); if (r < 0) { g_set_error(error, @@ -473,6 +452,9 @@ update_connection(NMDevice *device, NMConnection *connection) _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_INGRESS_MAP, NULL, 0); _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_EGRESS_MAP, NULL, 0); } + + if (polnk && polnk->lnk_vlan.protocol == ETH_P_8021AD) + g_object_set(s_vlan, NM_SETTING_VLAN_PROTOCOL, "802.1ad", NULL); } static NMActStageReturn @@ -592,7 +574,7 @@ nm_device_vlan_class_init(NMDeviceVlanClass *klass) #define NM_TYPE_VLAN_DEVICE_FACTORY (nm_vlan_device_factory_get_type()) #define NM_VLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VLAN_DEVICE_FACTORY, NMVlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VLAN_DEVICE_FACTORY, NMVlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vlan.h b/src/core/devices/nm-device-vlan.h index 5270706f..06fef5cf 100644 --- a/src/core/devices/nm-device-vlan.h +++ b/src/core/devices/nm-device-vlan.h @@ -9,7 +9,8 @@ #include "nm-device.h" #define NM_TYPE_DEVICE_VLAN (nm_device_vlan_get_type()) -#define NM_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan)) +#define NM_DEVICE_VLAN(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan)) #define NM_DEVICE_VLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass)) #define NM_IS_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VLAN)) diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index 91eb195a..ad31f3a2 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -347,7 +347,7 @@ nm_device_vrf_class_init(NMDeviceVrfClass *klass) #define NM_TYPE_VRF_DEVICE_FACTORY (nm_vrf_device_factory_get_type()) #define NM_VRF_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vrf.h b/src/core/devices/nm-device-vrf.h index 5169041c..c6580fb8 100644 --- a/src/core/devices/nm-device-vrf.h +++ b/src/core/devices/nm-device-vrf.h @@ -6,7 +6,7 @@ #include "nm-device-generic.h" #define NM_TYPE_DEVICE_VRF (nm_device_vrf_get_type()) -#define NM_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) +#define NM_DEVICE_VRF(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) #define NM_DEVICE_VRF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) #define NM_IS_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VRF)) diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index bf7c94c0..44a7be33 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -174,15 +174,15 @@ create_and_realize(NMDevice *device, str = nm_setting_vxlan_get_local(s_vxlan); if (str) { - if (!nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &props.local) - && !nm_utils_parse_inaddr_bin(AF_INET6, str, NULL, &props.local6)) + if (!nm_inet_parse_bin(AF_INET, str, NULL, &props.local) + && !nm_inet_parse_bin(AF_INET6, str, NULL, &props.local6)) return FALSE; } str = nm_setting_vxlan_get_remote(s_vxlan); if (str) { - if (!nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &props.group) - && !nm_utils_parse_inaddr_bin(AF_INET6, str, NULL, &props.group6)) + if (!nm_inet_parse_bin(AF_INET, str, NULL, &props.group) + && !nm_inet_parse_bin(AF_INET6, str, NULL, &props.group6)) return FALSE; } @@ -223,7 +223,7 @@ address_matches(const char *candidate, in_addr_t addr4, struct in6_addr *addr6) if (!candidate) return addr4 == 0u && IN6_IS_ADDR_UNSPECIFIED(addr6); - if (!nm_utils_parse_inaddr_bin(AF_UNSPEC, candidate, &addr_family, &candidate_addr)) + if (!nm_inet_parse_bin(AF_UNSPEC, candidate, &addr_family, &candidate_addr)) return FALSE; if (!nm_ip_addr_equal(addr_family, @@ -401,7 +401,7 @@ update_connection(NMDevice *device, NMConnection *connection) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(device); NMSettingVxlan *s_vxlan = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_VXLAN); - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; if (priv->props.id != nm_setting_vxlan_get_id(s_vxlan)) g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); @@ -417,12 +417,12 @@ update_connection(NMDevice *device, NMConnection *connection) if (priv->props.group) { g_object_set(s_vxlan, NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet4_ntop(priv->props.group, sbuf), + nm_inet4_ntop(priv->props.group, sbuf), NULL); } else { g_object_set(s_vxlan, NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet6_ntop(&priv->props.group6, sbuf), + nm_inet6_ntop(&priv->props.group6, sbuf), NULL); } } @@ -433,12 +433,12 @@ update_connection(NMDevice *device, NMConnection *connection) if (priv->props.local) { g_object_set(s_vxlan, NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet4_ntop(priv->props.local, sbuf), + nm_inet4_ntop(priv->props.local, sbuf), NULL); } else if (memcmp(&priv->props.local6, &in6addr_any, sizeof(in6addr_any))) { g_object_set(s_vxlan, NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet6_ntop(&priv->props.local6, sbuf), + nm_inet6_ntop(&priv->props.local6, sbuf), NULL); } } @@ -510,15 +510,15 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) break; case PROP_GROUP: if (priv->props.group) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.group)); + g_value_take_string(value, nm_inet4_ntop_dup(priv->props.group)); else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.group6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.group6)); + g_value_take_string(value, nm_inet6_ntop_dup(&priv->props.group6)); break; case PROP_LOCAL: if (priv->props.local) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.local)); + g_value_take_string(value, nm_inet4_ntop_dup(priv->props.local)); else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.local6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.local6)); + g_value_take_string(value, nm_inet6_ntop_dup(&priv->props.local6)); break; case PROP_TOS: g_value_set_uchar(value, priv->props.tos); @@ -741,7 +741,7 @@ nm_device_vxlan_class_init(NMDeviceVxlanClass *klass) #define NM_TYPE_VXLAN_DEVICE_FACTORY (nm_vxlan_device_factory_get_type()) #define NM_VXLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VXLAN_DEVICE_FACTORY, NMVxlanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VXLAN_DEVICE_FACTORY, NMVxlanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-vxlan.h b/src/core/devices/nm-device-vxlan.h index 4c4165e5..e53ae82e 100644 --- a/src/core/devices/nm-device-vxlan.h +++ b/src/core/devices/nm-device-vxlan.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_VXLAN (nm_device_vxlan_get_type()) #define NM_DEVICE_VXLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) #define NM_DEVICE_VXLAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) #define NM_IS_DEVICE_VXLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VXLAN)) diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 179c2a22..db02033d 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -219,7 +219,7 @@ _auto_default_route_get_enabled(NMSettingWireGuard *s_wg, aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); if (!valid) continue; - if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, aip, &addr_family, NULL, &prefix)) + if (!nm_inet_parse_with_prefix_bin(AF_UNSPEC, aip, &addr_family, NULL, &prefix)) continue; if (prefix != 0) continue; @@ -1152,11 +1152,11 @@ _peers_get_platform_list(NMDeviceWireGuardPrivate *priv, aip = nm_wireguard_peer_get_allowed_ip(peer_data->peer, i_aip, &valid); if (!valid - || !nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, - aip, - &addr_family, - &addrbin, - &prefix)) { + || !nm_inet_parse_with_prefix_bin(AF_UNSPEC, + aip, + &addr_family, + &addrbin, + &prefix)) { /* the address is really not expected to be invalid, because then * the connection would not verify. Anyway, silently skip it. */ continue; @@ -1197,7 +1197,7 @@ skip: nm_assert(plp->_construct_idx_start < plp->_construct_idx_end); l = plp->_construct_idx_end - plp->_construct_idx_start; plp->allowed_ips = - &g_array_index(allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); + &nm_g_array_index(allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); plp->allowed_ips_len = l; } } @@ -1701,8 +1701,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); - if (!valid - || !nm_utils_parse_inaddr_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) + if (!valid || !nm_inet_parse_with_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) continue; if (prefix < 0) @@ -1722,7 +1721,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES); } - nm_utils_ipx_address_clear_host_address(addr_family, &addrbin, NULL, prefix); + nm_ip_addr_clear_host_address(addr_family, &addrbin, NULL, prefix); rtable_coerced = route_table_coerced; @@ -2062,8 +2061,10 @@ nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass) /*************************************************************/ #define NM_TYPE_WIREGUARD_DEVICE_FACTORY (nm_wireguard_device_factory_get_type()) -#define NM_WIREGUARD_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIREGUARD_DEVICE_FACTORY, NMWireGuardDeviceFactory)) +#define NM_WIREGUARD_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), \ + NM_TYPE_WIREGUARD_DEVICE_FACTORY, \ + NMWireGuardDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-wireguard.h b/src/core/devices/nm-device-wireguard.h index 7e18bdba..8fb8f8cf 100644 --- a/src/core/devices/nm-device-wireguard.h +++ b/src/core/devices/nm-device-wireguard.h @@ -10,7 +10,7 @@ #define NM_TYPE_DEVICE_WIREGUARD (nm_device_wireguard_get_type()) #define NM_DEVICE_WIREGUARD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) #define NM_DEVICE_WIREGUARD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) #define NM_IS_DEVICE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIREGUARD)) diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index ecb5ee23..98356ccf 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -221,7 +221,7 @@ nm_device_wpan_class_init(NMDeviceWpanClass *klass) #define NM_TYPE_WPAN_DEVICE_FACTORY (nm_wpan_device_factory_get_type()) #define NM_WPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) static NMDevice * create_device(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-wpan.h b/src/core/devices/nm-device-wpan.h index 969929ae..39cf4656 100644 --- a/src/core/devices/nm-device-wpan.h +++ b/src/core/devices/nm-device-wpan.h @@ -7,7 +7,8 @@ #define __NETWORKMANAGER_DEVICE_WPAN_H__ #define NM_TYPE_DEVICE_WPAN (nm_device_wpan_get_type()) -#define NM_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) +#define NM_DEVICE_WPAN(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) #define NM_DEVICE_WPAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) #define NM_IS_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WPAN)) diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index c4f0f9a2..3565c04d 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -18,7 +18,7 @@ #include <netinet/in.h> #include <netinet/if_ether.h> #include <linux/if.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include <linux/rtnetlink.h> #include <linux/if_ether.h> #include <linux/if_infiniband.h> @@ -59,6 +59,7 @@ #include "settings/nm-settings.h" #include "nm-setting-ethtool.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-setting-user.h" #include "nm-auth-utils.h" #include "nm-keep-alive.h" @@ -77,6 +78,7 @@ #include "nm-device-generic.h" #include "nm-device-bridge.h" +#include "nm-device-loopback.h" #include "nm-device-vlan.h" #include "nm-device-vrf.h" #include "nm-device-wireguard.h" @@ -110,6 +112,7 @@ typedef enum { CLEANUP_TYPE_KEEP, CLEANUP_TYPE_REMOVED, CLEANUP_TYPE_DECONFIGURE, + CLEANUP_TYPE_KEEP_REAPPLY, } CleanupType; typedef enum _nm_packed { @@ -309,7 +312,7 @@ typedef struct { typedef enum { RESOLVER_WAIT_ADDRESS = 0, - RESOLVER_IN_PROGRESS, + RESOLVER_STARTED, RESOLVER_DONE, } ResolverState; @@ -848,7 +851,7 @@ static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self); static void _dev_ipshared6_start(NMDevice *self); static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply); +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp); static void concheck_update_state(NMDevice *self, int addr_family, @@ -1583,6 +1586,9 @@ _prop_get_ipv4_link_local(NMDevice *self) if (!s_ip4) return NM_SETTING_IP4_LL_DISABLED; + if (NM_IS_DEVICE_LOOPBACK(self)) + return NM_SETTING_IP4_LL_DISABLED; + link_local = nm_setting_ip4_config_get_link_local(s_ip4); if (link_local == NM_SETTING_IP4_LL_DEFAULT) { @@ -1804,6 +1810,7 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, const char *iface; const char *fail_reason; gboolean is_explicit = TRUE; + gint64 i64; s_ip = nm_connection_get_setting_ip_config(connection, addr_family); iaid_str = nm_setting_ip_config_get_dhcp_iaid(s_ip); @@ -1862,7 +1869,7 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, iaid = unaligned_read_be32(&hwaddr_buf[hwaddr_len - 4]); goto out_good; - } else if (nm_streq(iaid_str, "stable")) { + } else if (nm_streq(iaid_str, NM_IAID_STABLE)) { nm_auto_free_checksum GChecksum *sum = NULL; guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; NMUtilsStableType stable_type; @@ -1885,14 +1892,21 @@ _prop_get_ipvx_dhcp_iaid(NMDevice *self, iaid = unaligned_read_be32(digest); goto out_good; - } else if ((iaid = _nm_utils_ascii_str_to_int64(iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { - goto out_good; - } else { + } else if (nm_streq(iaid_str, NM_IAID_IFNAME)) { iface = nm_device_get_ip_iface(self); iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); goto out_good; + } else if (_nm_utils_iaid_verify(iaid_str, &i64)) { + if (i64 < 0) { + fail_reason = nm_assert_unreachable_val("bug handling iaid value"); + goto out_fail; + } + nm_assert(i64 <= G_MAXUINT32); + iaid = (guint32) i64; + goto out_good; } + fail_reason = nm_assert_unreachable_val("bug handling iaid code"); out_fail: nm_assert(fail_reason); if (!log_silent) { @@ -1906,11 +1920,13 @@ out_fail: iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); out_good: if (!log_silent) { + char buf[NM_DHCP_IAID_TO_HEXSTR_BUF_LEN]; + _LOGD(LOGD_DEVICE | LOGD_DHCPX(IS_IPv4) | LOGD_IPX(IS_IPv4), - "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", + "ipv%c.dhcp-iaid: using %u (%s) IAID (str: '%s', explicit %d)", nm_utils_addr_family_to_char(addr_family), iaid, - iaid, + nm_dhcp_iaid_to_hexstr(iaid, buf), iaid_str, is_explicit); } @@ -2736,12 +2752,6 @@ _ethtool_state_set(NMDevice *self) /*****************************************************************************/ -static gboolean -is_loopback(NMDevice *self) -{ - return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1; -} - gboolean nm_device_is_vpn(NMDevice *self) { @@ -3578,7 +3588,7 @@ _dev_ip_state_check_async(NMDevice *self, int addr_family) } static void -_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) +_dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean keep_reapply) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); int IS_IPv4; @@ -3586,7 +3596,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) if (addr_family == AF_UNSPEC) { _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); return; } @@ -3597,7 +3607,7 @@ _dev_ip_state_cleanup(NMDevice *self, int addr_family, gboolean from_reapply) nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].req_timeout_source); _dev_ip_state_set_state(self, addr_family, - from_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, + keep_reapply ? NM_DEVICE_IP_STATE_PENDING : NM_DEVICE_IP_STATE_NONE, "ip-state-clear"); priv->ip_data_x[IS_IPv4].wait_for_carrier = FALSE; priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE; @@ -4129,18 +4139,30 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N /* Check if AC6 addresses completed DAD */ if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags, nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ADDRESS)) - && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd - && nm_l3cfg_check_ready(l3cfg, - priv->ipac6_data.l3cd, - AF_INET6, - NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, - NULL)) { - if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) - _dev_l3_cfg_commit(self, FALSE); - - nm_clear_l3cd(&priv->ipac6_data.l3cd); - _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); - _dev_ip_state_check_async(self, AF_INET6); + && priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd) { + gs_unref_array GArray *conflicts = NULL; + gboolean ready; + + ready = nm_l3cfg_check_ready(l3cfg, + priv->ipac6_data.l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + &conflicts); + if (conflicts) { + /* nm_ndisc_dad_failed() will emit a new "NDisc:config-received" + * signal; _dev_ipac6_ndisc_config_changed() will be called + * synchronously to update the current state and schedule a commit. */ + nm_ndisc_dad_failed(priv->ipac6_data.ndisc, conflicts, TRUE); + } else if (ready) { + if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6)) + _dev_l3_cfg_commit(self, FALSE); + + nm_clear_l3cd(&priv->ipac6_data.l3cd); + _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); + _dev_ip_state_check_async(self, AF_INET6); + } else { + /* wait */ + } } _dev_ipmanual_check_ready(self); @@ -5005,6 +5027,9 @@ nm_device_get_route_metric_default(NMDeviceType device_type) */ switch (device_type) { + case NM_DEVICE_TYPE_LOOPBACK: + return 30; + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). * * Note that returning 50 from this function means that this device-type is @@ -5425,7 +5450,7 @@ concheck_is_possible(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!nm_device_is_real(self) || is_loopback(self)) + if (!nm_device_is_real(self) || NM_IS_DEVICE_LOOPBACK(self)) return FALSE; /* we enable periodic checks for every device state (except UNKNOWN). Especially with @@ -6203,7 +6228,8 @@ nm_device_master_release_slave(NMDevice *self, NMDevicePrivate *priv; NMDevicePrivate *slave_priv; SlaveInfo *info; - gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *self_free = NULL; + gs_unref_object NMDevice *slave_free = NULL; g_return_if_fail(NM_DEVICE(self)); g_return_if_fail(NM_DEVICE(slave)); @@ -6246,14 +6272,15 @@ nm_device_master_release_slave(NMDevice *self, /* keep both alive until the end of the function. * Transfers ownership from slave_priv->master. */ - self_free = self; + nm_assert(self == slave_priv->master); + self_free = g_steal_pointer(&slave_priv->master); - c_list_unlink(&info->lst_slave); - slave_priv->master = NULL; + nm_assert(slave == info->slave); + slave_free = g_steal_pointer(&info->slave); + c_list_unlink(&info->lst_slave); g_signal_handler_disconnect(slave, info->watch_id); - g_object_unref(slave); - g_slice_free(SlaveInfo, info); + nm_g_slice_free(info); if (c_list_is_empty(&priv->slaves)) { _active_connection_set_state_flags_full(self, @@ -6577,27 +6604,30 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (master && NM_DEVICE_GET_CLASS(master)->attach_port) { - nm_device_master_add_slave(master, self, FALSE); + if (master) { + if (NM_DEVICE_GET_CLASS(master)->attach_port) { + nm_device_master_add_slave(master, self, FALSE); + } else { + _LOGD(LOGD_DEVICE, + "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface(master)); + } goto out; } - if (master) { - _LOGD(LOGD_DEVICE, - "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface(master)); - } else { + if (plink->master) { _LOGD(LOGD_DEVICE, "enslaved to unknown device %d (%s%s%s)", plink->master, NM_PRINT_FMT_QUOTED(plink_master, "\"", plink_master->name, "\"", "??")); + if (!priv->ifindex_changed_id) { + priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), + NM_MANAGER_DEVICE_IFINDEX_CHANGED, + G_CALLBACK(device_ifindex_changed_cb), + self); + } } - if (!priv->ifindex_changed_id) { - priv->ifindex_changed_id = g_signal_connect(nm_device_get_manager(self), - NM_MANAGER_DEVICE_IFINDEX_CHANGED, - G_CALLBACK(device_ifindex_changed_cb), - self); - } + return; out: @@ -6609,6 +6639,8 @@ device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + g_return_if_fail(priv->master_ifindex > 0); + if (priv->master_ifindex != nm_device_get_ifindex(device_changed)) return; @@ -7146,6 +7178,9 @@ nm_device_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) ifindex_changed = _set_ifindex(self, plink ? plink->ifindex : 0, FALSE); + nm_device_update_hw_address(self); + nm_device_update_permanent_hw_address(self, FALSE); + if (ifindex_changed) NM_DEVICE_GET_CLASS(self)->link_changed(self, plink); @@ -7465,11 +7500,6 @@ realize_start_setup(NMDevice *self, NM_UNMANAGED_EXTERNAL_DOWN, _dev_unmanaged_is_external_down(self, TRUE)); - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. - * Later we might want to manage 'lo' too. Currently, that doesn't work because - * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self)); - nm_device_set_unmanaged_by_user_udev(self); nm_device_set_unmanaged_by_user_conf(self); @@ -7659,8 +7689,7 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); nm_device_set_unmanaged_flags(self, - NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE - | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT + NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET); @@ -8565,6 +8594,7 @@ nm_device_generate_connection(NMDevice *self, nm_device_get_iface(master), local->message); g_error_free(local); + NM_SET_OUT(out_maybe_later, TRUE); return NULL; } } else { @@ -8585,7 +8615,7 @@ nm_device_generate_connection(NMDevice *self, pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ifindex); if (pllink && pllink->inet6_token.id) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, @@ -8776,6 +8806,14 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e return FALSE; } + if (!nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) + && nm_connection_get_setting(connection, NM_TYPE_SETTING_SRIOV)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support SR-IOV"); + return FALSE; + } + conn_iface = nm_manager_get_connection_iface(NM_MANAGER_GET, connection, NULL, NULL, &local); /* We always need a interface name for virtual devices, but for @@ -9359,14 +9397,17 @@ activate_stage1_device_prepare(NMDevice *self) nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { - NMSettingSriov *s_sriov; + NMSettingSriov *s_sriov = NULL; if (nm_device_sys_iface_state_is_external_or_assume(self)) { /* pass */ - } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) + } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) { return; - else if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + } else if (priv->ifindex > 0) { + s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV); + } + + if (s_sriov) { nm_auto_freev NMPlatformVF **plat_vfs = NULL; gs_free_error GError *error = NULL; NMSriovVF *vf; @@ -9374,6 +9415,8 @@ activate_stage1_device_prepare(NMDevice *self) guint num; guint i; + nm_assert(nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)); + autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov); if (autoprobe == NM_TERNARY_DEFAULT) { autoprobe = nm_config_data_get_connection_default_int64( @@ -9612,6 +9655,18 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) user_tag_1, NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); } + + if (nm_setting_ip_config_get_replace_local_rule(s_ip) == NM_TERNARY_TRUE) { + /* The user specified that the local rule should be replaced. + * In order to do that, we track the local rule with negative + * priority. */ + nmp_global_tracker_track_local_rule( + global_tracker, + addr_family, + -5, + user_tag_1, + NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } } if (klass->get_extra_rules) { @@ -10058,7 +10113,7 @@ _dev_ipmanual_check_ready(NMDevice *self) gboolean has_carrier; NML3CfgCheckReadyFlags flags; gboolean ready; - gboolean acd_used = FALSE; + gs_unref_array GArray *conflicts = NULL; int IS_IPv4; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING @@ -10101,8 +10156,8 @@ _dev_ipmanual_check_ready(NMDevice *self) priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, addr_family, flags, - &acd_used); - if (acd_used) { + &conflicts); + if (conflicts) { _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); _dev_ip_state_check_async(self, AF_UNSPEC); } else if (ready) { @@ -10434,6 +10489,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .request_broadcast = request_broadcast, .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), }, + .previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d, }; priv->ipdhcp_data_4.client = @@ -10484,16 +10540,16 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) G_CALLBACK(_dev_ipdhcpx_notify), self); - /* FIXME(l3cfg:dhcp:previous-lease): take the NML3ConfigData from the previous lease (if any) - * and pass it on to NMDhcpClient. This is a fake lease that we use initially (until - * NMDhcpClient got a real lease). Note that NMDhcpClient needs to check whether the - * lease already expired. */ - + /* Take the NML3ConfigData from the previous lease (if any) that was passed to the NMDhcpClient. + * This may be the old lease only used during the duration of a reapply until we get the + * new lease. */ previous_lease = nm_dhcp_client_get_lease(priv->ipdhcp_data_x[IS_IPv4].client); + if (!priv->ipdhcp_data_x[IS_IPv4].config) { priv->ipdhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family, previous_lease); _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); } + if (previous_lease) { nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, previous_lease); _dev_l3_register_l3cds_set_one_full(self, @@ -10747,14 +10803,14 @@ nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) l3cd_src = priv_src->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d; } if (l3cd_src) { - const char *const *strvarr; - const struct in6_addr *addrs; - guint n; - guint i; + const char *const *strvarr; + const char *const *addrs; + guint n; + guint i; addrs = nm_l3_config_data_get_nameservers(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addrs[i]); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, addrs[i]); strvarr = nm_l3_config_data_get_searches(l3cd_src, AF_INET6, &n); for (i = 0; i < n; i++) @@ -10806,7 +10862,8 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 || (!priv->ipll_data_6.v6.ipv6ll && NM_IN_SET(priv->ipll_data_6.v6.llstate, NM_L3_IPV6LL_STATE_NONE, - NM_L3_IPV6LL_STATE_DEFUNCT))); + NM_L3_IPV6LL_STATE_DEFUNCT, + NM_L3_IPV6LL_STATE_READY))); switch (priv->ipll_data_6.v6.llstate) { case NM_L3_IPV6LL_STATE_NONE: @@ -10844,7 +10901,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 } if (changed) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; _LOGT_ipll(AF_INET6, "set state %s (was %s, llstate=%s, lladdr=%s)", @@ -10853,7 +10910,7 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6 nm_l3_ipv6ll_state_to_string(priv->ipll_data_6.v6.llstate), nm_ip_addr_is_null(AF_INET6, &priv->ipll_data_6.v6.lladdr) ? "(none)" - : _nm_utils_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); + : nm_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf)); } if (changed) @@ -10889,6 +10946,11 @@ _dev_ipll6_start(NMDevice *self) if (priv->ipll_data_6.v6.ipv6ll) return; + if (NM_IS_DEVICE_LOOPBACK(self)) { + _dev_ipll6_set_llstate(self, NM_L3_IPV6LL_STATE_READY, NULL); + return; + } + if (!priv->l3cfg) { _LOGD(LOGD_IP6, "linklocal6: no IP link for IPv6"); goto out_fail; @@ -11000,6 +11062,10 @@ nm_device_get_configured_mtu_from_connection(NMDevice *self, if (setting) mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting)); global_property_name = NM_CON_DEFAULT("wireguard.mtu"); + } else if (setting_type == NM_TYPE_SETTING_LOOPBACK) { + if (setting) + mtu = nm_setting_loopback_get_mtu(NM_SETTING_LOOPBACK(setting)); + global_property_name = NM_CON_DEFAULT("loopback.mtu"); } else g_return_val_if_reached(0); @@ -11411,10 +11477,14 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, const NML3ConfigData *l3cd, NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ready = TRUE; - NMDedupMultiIter iter; - const NMPObject *obj; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ready; + + /* The ndisc configuration changes when we receive a new RA or + * when a lifetime expires; but also when DAD fails for a + * SLAAC address and we need to regenerate new stable-privacy + * addresses. In all these cases we update the AC6 configuration, + * schedule a commit and update the AC state. */ _dev_ipac6_grace_period_start(self, 0, TRUE); @@ -11425,22 +11495,11 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, FALSE); nm_clear_l3cd(&priv->ipac6_data.l3cd); - - /* wait that addresses are committed to platform and - * become non-tentative before declaring AC6 is ready.*/ - nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); - const NMPlatformIP6Address *plat_addr; - - plat_addr = nm_platform_ip6_address_get(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &addr->address); - if (!plat_addr || (plat_addr->n_ifa_flags & IFA_F_TENTATIVE)) { - ready = FALSE; - break; - } - } - + ready = nm_l3cfg_check_ready(priv->l3cfg, + l3cd, + AF_INET6, + NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, + NULL); if (ready) { _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); } else { @@ -12078,13 +12137,34 @@ activate_stage3_ip_config(NMDevice *self) ifindex = nm_device_get_ip_ifindex(self); + ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses + * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ + ipv4_method = klass->get_ip_method_auto(self, AF_INET); + } + + ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); + + if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + ipv6_method = klass->get_ip_method_auto(self, AF_INET6); + } + if (priv->ip_data_4.do_reapply) { _LOGD_ip(AF_INET, "reapply..."); - _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_4.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)); } if (priv->ip_data_6.do_reapply) { _LOGD_ip(AF_INET6, "reapply..."); - _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE, TRUE); + priv->ip_data_6.do_reapply = FALSE; + _cleanup_ip_pre(self, + AF_INET6, + CLEANUP_TYPE_KEEP_REAPPLY, + nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); } /* Add the interface to the specified firewall zone */ @@ -12136,18 +12216,6 @@ activate_stage3_ip_config(NMDevice *self) * let's do it! */ _commit_mtu(self); - ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses - * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ - ipv4_method = klass->get_ip_method_auto(self, AF_INET); - } - - ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); - if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - ipv6_method = klass->get_ip_method_auto(self, AF_INET6); - } - if (!nm_device_sys_iface_state_is_external(self) && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self, TRUE))) { if (priv->ipmanual_data.state_6 == NM_DEVICE_IP_STATE_NONE @@ -12274,16 +12342,28 @@ _dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4A static gboolean _dev_ipshared4_init(NMDevice *self) { - static const char *const modules[] = {"ip_tables", - "iptable_nat", - "nf_nat_ftp", - "nf_nat_irc", - "nf_nat_sip", - "nf_nat_tftp", - "nf_nat_pptp", - "nf_nat_h323"}; - int errsv; - guint i; + static const char *const modules_iptables[] = {"ip_tables", "iptable_nat"}; + static const char *const modules_nftables[] = + {"nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323"}; + int errsv; + guint i; + + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_IPTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_iptables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_iptables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NFTABLES: + for (i = 0; i < G_N_ELEMENTS(modules_nftables); i++) + nmp_utils_modprobe(NULL, FALSE, modules_nftables[i], NULL); + break; + case NM_FIREWALL_BACKEND_NONE: + /* do not modify network settings like ip forwarding */ + return TRUE; + default: + nm_assert_not_reached(); + break; + } if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), @@ -12312,9 +12392,6 @@ _dev_ipshared4_init(NMDevice *self) nm_strerror_native(errsv)); } - for (i = 0; i < G_N_ELEMENTS(modules); i++) - nmp_utils_modprobe(NULL, FALSE, modules[i], NULL); - return TRUE; } @@ -12591,17 +12668,18 @@ delete_on_deactivate_check_and_schedule(NMDevice *self) } static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply) +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean preserve_dhcp) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean keep_reapply = (cleanup_type == CLEANUP_TYPE_KEEP_REAPPLY); _dev_ipsharedx_cleanup(self, addr_family); _dev_ipdev_cleanup(self, AF_UNSPEC); _dev_ipdev_cleanup(self, addr_family); - _dev_ipdhcpx_cleanup(self, addr_family, TRUE, FALSE); + _dev_ipdhcpx_cleanup(self, addr_family, !preserve_dhcp || !keep_reapply, FALSE); if (!IS_IPv4) _dev_ipac6_cleanup(self); @@ -12613,8 +12691,8 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager), &priv->ip_data.dnsmgr_update_pending_signal_id); - _dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply); - _dev_ip_state_cleanup(self, addr_family, from_reapply); + _dev_ip_state_cleanup(self, AF_UNSPEC, keep_reapply); + _dev_ip_state_cleanup(self, addr_family, keep_reapply); } gboolean @@ -12762,7 +12840,9 @@ can_reapply_change(NMDevice *self, goto out_fail; } - if (nm_streq(setting_name, NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME) + if (NM_IN_STRSET(setting_name, + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_OTHER_CONFIG_SETTING_NAME) && NM_DEVICE_GET_CLASS(self)->can_reapply_change_ovs_external_ids) { /* TODO: this means, you cannot reapply changes to the external-ids for * OVS system interfaces. */ @@ -12984,6 +13064,10 @@ check_and_reapply_connection(NMDevice *self, if (priv->state >= NM_DEVICE_STATE_ACTIVATED) nm_device_update_metered(self); + /* Notify dispatcher when re-applied */ + _LOGD(LOGD_DEVICE, "Notifying re-apply complete"); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_REAPPLY, self, NULL, NULL, NULL, NULL); + return TRUE; } @@ -13889,7 +13973,7 @@ nm_device_start_ip_check(NMDevice *self) NMSettingConnection *s_con; guint timeout = 0; const char *ping_binary = NULL; - char buf[NM_UTILS_INET_ADDRSTRLEN]; + char buf[NM_INET_ADDRSTRLEN]; NMLogDomain log_domain = LOGD_IP4; /* Shouldn't be any active ping here, since IP_CHECK happens after the @@ -13920,14 +14004,14 @@ nm_device_start_ip_check(NMDevice *self) } else if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET); if (gw) { - _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); + nm_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } } else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY) { gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6); if (gw) { - _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); + nm_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); log_domain = LOGD_IP6; } @@ -14151,8 +14235,6 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, NMUnmanagedFlags, NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"), @@ -14847,9 +14929,10 @@ _nm_device_check_connection_available(NMDevice *self, } else { if (!nm_device_get_managed(self, TRUE)) { /* device is strictly unmanaged by authoritative unmanaged reasons. */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is strictly unmanaged"); + nm_utils_error_set_literal( + error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_STRICTLY_UNMANAGED_DEVICE, + "device is strictly unmanaged"); return FALSE; } if (!NM_FLAGS_HAS(flags, @@ -16138,7 +16221,7 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r /* We should only ever have one delayed state transition at a time */ if (priv->queued_state.id) { - _LOGW(LOGD_DEVICE, + _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_string(priv->queued_state.state), nm_device_state_reason_to_string_a(priv->queued_state.reason), @@ -17036,6 +17119,21 @@ nm_device_auth_retries_try_next(NMDevice *self) return TRUE; } +static const char * +_resolver_state_to_string(ResolverState state) +{ + switch (state) { + case RESOLVER_WAIT_ADDRESS: + return "WAIT-ADDRESS"; + case RESOLVER_STARTED: + return "STARTED"; + case RESOLVER_DONE: + return "DONE"; + } + nm_assert_not_reached(); + return "UNKNOWN"; +} + static void hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer user_data) { @@ -17055,7 +17153,9 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use if (error) { _LOGD(LOGD_DNS, - "hostname-from-dns: lookup error for %s: %s", + "hostname-from-dns: ipv%c resolver %s: lookup error for %s: %s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE), (addr_str = g_inet_address_to_string(resolver->address)), error->message); } else { @@ -17065,7 +17165,9 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use valid = nm_utils_validate_hostname(resolver->hostname); _LOGD(LOGD_DNS, - "hostname-from-dns: lookup done for %s, result %s%s%s%s", + "hostname-from-dns: ipv%c resolver %s: lookup successful for %s, result %s%s%s%s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE), (addr_str = g_inet_address_to_string(resolver->address)), NM_PRINT_FMT_QUOTE_STRING(resolver->hostname), valid ? "" : " (invalid)"); @@ -17091,8 +17193,9 @@ hostname_dns_address_timeout(gpointer user_data) nm_assert(!resolver->cancellable); _LOGT(LOGD_DNS, - "hostname-from-dns: timed out while waiting IPv%c address", - nm_utils_addr_family_to_char(resolver->addr_family)); + "hostname-from-dns: ipv%c state %s: timed out while waiting for address", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(RESOLVER_DONE)); resolver->timeout_id = 0; resolver->state = RESOLVER_DONE; @@ -17101,30 +17204,22 @@ hostname_dns_address_timeout(gpointer user_data) return G_SOURCE_REMOVE; } -static const char * -_resolver_state_to_string(ResolverState state) +void +nm_device_clear_dns_lookup_data(NMDevice *self, const char *reason) { - switch (state) { - case RESOLVER_WAIT_ADDRESS: - return "wait-address"; - case RESOLVER_IN_PROGRESS: - return "in-progress"; - case RESOLVER_DONE: - return "done"; - default: - nm_assert_not_reached(); - return "unknown"; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->hostname_resolver_4 || priv->hostname_resolver_6) { + _LOGT(LOGD_DNS, "hostname-from-dns: resetting (%s)", reason); + nm_clear_pointer(&priv->hostname_resolver_4, _hostname_resolver_free); + nm_clear_pointer(&priv->hostname_resolver_6, _hostname_resolver_free); } } -void -nm_device_clear_dns_lookup_data(NMDevice *self) +gboolean +nm_device_get_allow_autoconnect_on_external(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint i; - - for (i = 0; i < 2; i++) - nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free); + return NM_DEVICE_GET_CLASS(self)->allow_autoconnect_on_external; } static GInetAddress * @@ -17151,27 +17246,36 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) if (head_entry) { c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) { - const NMPlatformIPAddress *addr = NMP_OBJECT_CAST_IP_ADDRESS(iter->obj); + const NMPlatformIPXAddress *addr = NMP_OBJECT_CAST_IPX_ADDRESS(iter->obj); if (IS_IPv4) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV4); + if (nm_ip4_addr_is_loopback(addr->a4.address)) + continue; + return g_inet_address_new_from_bytes(addr->ax.address_ptr, G_SOCKET_FAMILY_IPV4); } + if (addr->ax.n_ifa_flags & IFA_F_TENTATIVE) + continue; + /* For IPv6 prefer, in order: * - !link-local, !deprecated * - !link-local, deprecated * - link-local */ - if (!IN6_IS_ADDR_LINKLOCAL(addr->address_ptr)) { - if (!(addr->n_ifa_flags & IFA_F_DEPRECATED)) { - return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV6); + if (IN6_ARE_ADDR_EQUAL(&addr->a6.address, &in6addr_loopback)) + continue; + + if (!IN6_IS_ADDR_LINKLOCAL(addr->ax.address_ptr)) { + if (!(addr->ax.n_ifa_flags & IFA_F_DEPRECATED)) { + return g_inet_address_new_from_bytes(addr->ax.address_ptr, + G_SOCKET_FAMILY_IPV6); } - addr6_nonll = addr->address_ptr; + addr6_nonll = addr->ax.address_ptr; continue; } - addr6_ll = addr->address_ptr; + addr6_ll = addr->ax.address_ptr; } if (addr6_nonll || addr6_ll) @@ -17246,29 +17350,35 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean } else if (new_address != resolver->address) address_changed = TRUE; + if (address_changed) { + /* set new state before logging */ + if (new_address) + resolver->state = RESOLVER_STARTED; + else + resolver->state = RESOLVER_WAIT_ADDRESS; + } + { gs_free char *old_str = NULL; gs_free char *new_str = NULL; - _LOGT(LOGD_DNS, - "hostname-from-dns: ipv%c resolver state %s, old address %s, new address %s", - nm_utils_addr_family_to_char(resolver->addr_family), - _resolver_state_to_string(resolver->state), - resolver->address ? (old_str = g_inet_address_to_string(resolver->address)) - : "(null)", - new_address ? (new_str = g_inet_address_to_string(new_address)) : "(null)"); + if (address_changed) { + _LOGT(LOGD_DNS, + "hostname-from-dns: ipv%c resolver %s, address changed from %s to %s", + nm_utils_addr_family_to_char(resolver->addr_family), + _resolver_state_to_string(resolver->state), + resolver->address ? (old_str = g_inet_address_to_string(resolver->address)) + : "(null)", + new_address ? (new_str = g_inet_address_to_string(new_address)) : "(null)"); + } } - /* In every state, if the address changed, we restart - * the resolution with the new address */ if (address_changed) { nm_clear_g_cancellable(&resolver->cancellable); g_clear_object(&resolver->address); - resolver->state = RESOLVER_WAIT_ADDRESS; } if (address_changed && new_address) { - resolver->state = RESOLVER_IN_PROGRESS; resolver->cancellable = g_cancellable_new(); resolver->address = g_steal_pointer(&new_address); @@ -17286,7 +17396,7 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean resolver->timeout_id = g_timeout_add(30000, hostname_dns_address_timeout, resolver); NM_SET_OUT(out_wait, TRUE); return NULL; - case RESOLVER_IN_PROGRESS: + case RESOLVER_STARTED: NM_SET_OUT(out_wait, TRUE); return NULL; case RESOLVER_DONE: @@ -17578,7 +17688,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_VRF); + nm_assert(priv->type <= NM_DEVICE_TYPE_LOOPBACK); break; case PROP_LINK_TYPE: /* construct-only */ diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index de850e68..bcf4d7b9 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -91,7 +91,7 @@ #define NM_DEVICE_INTERFACE_FLAGS "interface-flags" #define NM_TYPE_DEVICE (nm_device_get_type()) -#define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE, NMDevice)) +#define NM_DEVICE(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE, NMDevice)) #define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE, NMDeviceClass)) #define NM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE)) #define NM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE)) @@ -208,6 +208,8 @@ typedef struct _NMDeviceClass { bool can_reapply_change_ovs_external_ids : 1; + bool allow_autoconnect_on_external : 1; + NMRfkillType rfkill_type : 4; void (*state_changed)(NMDevice *device, @@ -561,8 +563,6 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); * @NM_UNMANAGED_NONE: placeholder value * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping. * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down. - * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged - * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback. * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not * yet initialized. Unrealized device are also unmanaged for this reason. * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision @@ -592,21 +592,19 @@ typedef enum { * the device cannot be managed. */ NM_UNMANAGED_SLEEPING = (1LL << 0), NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_BY_TYPE = (1LL << 3), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), - NM_UNMANAGED_USER_SETTINGS = (1LL << 6), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 2), + NM_UNMANAGED_USER_EXPLICIT = (1LL << 3), + NM_UNMANAGED_USER_SETTINGS = (1LL << 4), /* These flags can be non-effective and be overwritten * by other flags. */ - NM_UNMANAGED_BY_DEFAULT = (1LL << 7), - NM_UNMANAGED_USER_CONF = (1LL << 8), - NM_UNMANAGED_USER_UDEV = (1LL << 9), - NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 10), - NM_UNMANAGED_IS_SLAVE = (1LL << 11), + NM_UNMANAGED_BY_DEFAULT = (1LL << 5), + NM_UNMANAGED_USER_CONF = (1LL << 6), + NM_UNMANAGED_USER_UDEV = (1LL << 7), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 8), + NM_UNMANAGED_IS_SLAVE = (1LL << 9), - NM_UNMANAGED_ALL = ((1LL << 12) - 1), + NM_UNMANAGED_ALL = ((1LL << 10) - 1), } NMUnmanagedFlags; typedef enum { @@ -819,6 +817,8 @@ gboolean nm_device_is_vpn(NMDevice *self); const char * nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean *out_pending); -void nm_device_clear_dns_lookup_data(NMDevice *self); +void nm_device_clear_dns_lookup_data(NMDevice *self, const char *reason); + +gboolean nm_device_get_allow_autoconnect_on_external(NMDevice *self); #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index 137bf8fb..ac7e97f0 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -15,24 +15,20 @@ #include "libnm-std-aux/unaligned.h" #include "libnm-platform/nm-platform.h" #include "libnm-glib-aux/nm-c-list.h" +#include "libnm-lldp/nm-lldp-rx.h" #include "nm-utils.h" -#include "libnm-systemd-core/nm-sd.h" - #define MAX_NEIGHBORS 128 #define MIN_UPDATE_INTERVAL_NSEC (2 * NM_UTILS_NSEC_PER_SEC) -#define LLDP_MAC_NEAREST_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}})) -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}})) -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}})) +#define LLDP_MAC_NEAREST_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e)) +#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x03)) +#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (&NM_ETHER_ADDR_INIT(0x01, 0x80, 0xc2, 0x00, 0x00, 0x00)) /*****************************************************************************/ struct _NMLldpListener { - sd_lldp_rx *lldp_handle; + NMLldpRX *lldp_rx; GHashTable *lldp_neighbors; GVariant *variant; @@ -49,12 +45,12 @@ struct _NMLldpListener { /*****************************************************************************/ typedef struct { - GVariant *variant; - sd_lldp_neighbor *neighbor_sd; - char *chassis_id; - char *port_id; - guint8 chassis_id_type; - guint8 port_id_type; + GVariant *variant; + NMLldpNeighbor *neighbor_nm; + char *chassis_id; + char *port_id; + guint8 chassis_id_type; + guint8 port_id_type; } LldpNeighbor; /*****************************************************************************/ @@ -100,7 +96,7 @@ lldp_neighbor_get_raw(LldpNeighbor *neigh, const guint8 **out_raw_data, gsize *o nm_assert(neigh); - r = sd_lldp_neighbor_get_raw(neigh->neighbor_sd, &raw_data, &raw_len); + r = nm_lldp_neighbor_get_raw(neigh->neighbor_nm, &raw_data, &raw_len); nm_assert(r >= 0); nm_assert(raw_data); @@ -111,24 +107,24 @@ lldp_neighbor_get_raw(LldpNeighbor *neigh, const guint8 **out_raw_data, gsize *o } static gboolean -lldp_neighbor_id_get(struct sd_lldp_neighbor *neighbor_sd, - guint8 *out_chassis_id_type, - const guint8 **out_chassis_id, - gsize *out_chassis_id_len, - guint8 *out_port_id_type, - const guint8 **out_port_id, - gsize *out_port_id_len) +lldp_neighbor_id_get(NMLldpNeighbor *neighbor_nm, + guint8 *out_chassis_id_type, + const guint8 **out_chassis_id, + gsize *out_chassis_id_len, + guint8 *out_port_id_type, + const guint8 **out_port_id, + gsize *out_port_id_len) { int r; - r = sd_lldp_neighbor_get_chassis_id(neighbor_sd, + r = nm_lldp_neighbor_get_chassis_id(neighbor_nm, out_chassis_id_type, (gconstpointer *) out_chassis_id, out_chassis_id_len); if (r < 0) return FALSE; - r = sd_lldp_neighbor_get_port_id(neighbor_sd, + r = nm_lldp_neighbor_get_port_id(neighbor_nm, out_port_id_type, (gconstpointer *) out_port_id, out_port_id_len); @@ -139,82 +135,16 @@ lldp_neighbor_id_get(struct sd_lldp_neighbor *neighbor_sd, } static guint -lldp_neighbor_id_hash(gconstpointer ptr) +lldp_neighbor_id_hash(const LldpNeighbor *neigh) { - const LldpNeighbor *neigh = ptr; - guint8 chassis_id_type; - guint8 port_id_type; - const guint8 *chassis_id; - const guint8 *port_id; - gsize chassis_id_len; - gsize port_id_len; - NMHashState h; - - if (!lldp_neighbor_id_get(neigh->neighbor_sd, - &chassis_id_type, - &chassis_id, - &chassis_id_len, - &port_id_type, - &port_id, - &port_id_len)) { - nm_assert_not_reached(); - return 0; - } - - nm_hash_init(&h, 23423423u); - nm_hash_update_vals(&h, chassis_id_len, port_id_len, chassis_id_type, port_id_type); - nm_hash_update(&h, chassis_id, chassis_id_len); - nm_hash_update(&h, port_id, port_id_len); - return nm_hash_complete(&h); + return nm_lldp_neighbor_id_hash(nm_lldp_neighbor_get_id(neigh->neighbor_nm)); } static int lldp_neighbor_id_cmp(const LldpNeighbor *a, const LldpNeighbor *b) { - guint8 a_chassis_id_type; - guint8 b_chassis_id_type; - guint8 a_port_id_type; - guint8 b_port_id_type; - const guint8 *a_chassis_id; - const guint8 *b_chassis_id; - const guint8 *a_port_id; - const guint8 *b_port_id; - gsize a_chassis_id_len; - gsize b_chassis_id_len; - gsize a_port_id_len; - gsize b_port_id_len; - - NM_CMP_SELF(a, b); - - if (!lldp_neighbor_id_get(a->neighbor_sd, - &a_chassis_id_type, - &a_chassis_id, - &a_chassis_id_len, - &a_port_id_type, - &a_port_id, - &a_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - if (!lldp_neighbor_id_get(b->neighbor_sd, - &b_chassis_id_type, - &b_chassis_id, - &b_chassis_id_len, - &b_port_id_type, - &b_port_id, - &b_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - NM_CMP_DIRECT(a_chassis_id_type, b_chassis_id_type); - NM_CMP_DIRECT(a_port_id_type, b_port_id_type); - NM_CMP_DIRECT(a_chassis_id_len, b_chassis_id_len); - NM_CMP_DIRECT(a_port_id_len, b_port_id_len); - NM_CMP_DIRECT_MEMCMP(a_chassis_id, b_chassis_id, a_chassis_id_len); - NM_CMP_DIRECT_MEMCMP(a_port_id, b_port_id, a_port_id_len); - return 0; + return nm_lldp_neighbor_id_cmp(nm_lldp_neighbor_get_id(a->neighbor_nm), + nm_lldp_neighbor_get_id(b->neighbor_nm)); } static int @@ -225,7 +155,7 @@ lldp_neighbor_id_cmp_p(gconstpointer a, gconstpointer b, gpointer user_data) } static gboolean -lldp_neighbor_id_equal(gconstpointer a, gconstpointer b) +lldp_neighbor_id_equal(const LldpNeighbor *a, const LldpNeighbor *b) { return lldp_neighbor_id_cmp(a, b) == 0; } @@ -239,7 +169,7 @@ lldp_neighbor_free(LldpNeighbor *neighbor) g_free(neighbor->chassis_id); g_free(neighbor->port_id); nm_g_variant_unref(neighbor->variant); - sd_lldp_neighbor_unref(neighbor->neighbor_sd); + nm_lldp_neighbor_unref(neighbor->neighbor_nm); nm_g_slice_free(neighbor); } @@ -257,7 +187,7 @@ lldp_neighbor_equal(LldpNeighbor *a, LldpNeighbor *b) gsize raw_len_a; gsize raw_len_b; - if (a->neighbor_sd == b->neighbor_sd) + if (a->neighbor_nm == b->neighbor_nm) return TRUE; lldp_neighbor_get_raw(a, &raw_data_a, &raw_len_a); @@ -293,7 +223,7 @@ parse_management_address_tlv(const uint8_t *data, gsize len) if (len < 11) return NULL; - nm_assert((data[0] >> 1) == SD_LLDP_TYPE_MGMT_ADDRESS); + nm_assert((data[0] >> 1) == NM_LLDP_TYPE_MGMT_ADDRESS); nm_assert((((data[0] & 1) << 8) + data[1]) + 2 == len); data += 2; @@ -360,7 +290,7 @@ format_network_address(const guint8 *data, gsize sz) } else return NULL; - return nm_utils_inet_ntop_dup(family, &a); + return nm_inet_ntop_dup(family, &a); } static const char * @@ -402,7 +332,7 @@ format_string_cp(const guint8 *data, gsize len, gboolean allow_trim) } static LldpNeighbor * -lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) +lldp_neighbor_new(NMLldpNeighbor *neighbor_nm) { LldpNeighbor *neigh; guint8 chassis_id_type; @@ -414,7 +344,7 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) gs_free char *s_chassis_id = NULL; gs_free char *s_port_id = NULL; - if (!lldp_neighbor_id_get(neighbor_sd, + if (!lldp_neighbor_id_get(neighbor_nm, &chassis_id_type, &chassis_id, &chassis_id_len, @@ -424,17 +354,17 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) return NULL; switch (chassis_id_type) { - case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + case NM_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case NM_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case NM_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case NM_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case NM_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: s_chassis_id = format_string_cp(chassis_id, chassis_id_len, FALSE); break; - case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + case NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: s_chassis_id = nm_utils_hwaddr_ntoa(chassis_id, chassis_id_len); break; - case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + case NM_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: s_chassis_id = format_network_address(chassis_id, chassis_id_len); break; } @@ -446,16 +376,16 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) } switch (port_id_type) { - case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + case NM_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case NM_LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case NM_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: s_port_id = format_string_cp(port_id, port_id_len, FALSE); break; - case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: + case NM_LLDP_PORT_SUBTYPE_MAC_ADDRESS: s_port_id = nm_utils_hwaddr_ntoa(port_id, port_id_len); break; - case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + case NM_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: s_port_id = format_network_address(port_id, port_id_len); break; } @@ -468,7 +398,7 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) neigh = g_slice_new(LldpNeighbor); *neigh = (LldpNeighbor){ - .neighbor_sd = sd_lldp_neighbor_ref(neighbor_sd), + .neighbor_nm = nm_lldp_neighbor_ref(neighbor_nm), .chassis_id_type = chassis_id_type, .chassis_id = g_steal_pointer(&s_chassis_id), .port_id_type = port_id_type, @@ -480,15 +410,15 @@ lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) static GVariant * lldp_neighbor_to_variant(LldpNeighbor *neigh) { - struct ether_addr destination_address; - GVariantBuilder builder; - const char *str; - const guint8 *raw_data; - gsize raw_len; - uint16_t u16; - uint8_t *data8; - gsize len; - int r; + NMEtherAddr destination_address; + GVariantBuilder builder; + const char *str; + const guint8 *raw_data; + gsize raw_len; + uint16_t u16; + uint8_t *data8; + gsize len; + int r; if (neigh->variant) return neigh->variant; @@ -505,33 +435,33 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_PORT_ID_TYPE, neigh->port_id_type); nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_ID, neigh->port_id); - r = sd_lldp_neighbor_get_destination_address(neigh->neighbor_sd, &destination_address); + r = nm_lldp_neighbor_get_destination_address(neigh->neighbor_nm, &destination_address); if (r < 0) str = NULL; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_BRIDGE)) str = NM_LLDP_DEST_NEAREST_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) + else if (nm_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; else str = NULL; if (str) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_DESTINATION, str); - if (sd_lldp_neighbor_get_port_description(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_port_description(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_DESCRIPTION, str); - if (sd_lldp_neighbor_get_system_name(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_system_name(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_NAME, str); - if (sd_lldp_neighbor_get_system_description(neigh->neighbor_sd, &str) == 0) + if (nm_lldp_neighbor_get_system_description(neigh->neighbor_nm, &str) == 0) nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, str); - if (sd_lldp_neighbor_get_system_capabilities(neigh->neighbor_sd, &u16) == 0) + if (nm_lldp_neighbor_get_system_capabilities(neigh->neighbor_nm, &u16) == 0) nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, u16); - r = sd_lldp_neighbor_tlv_rewind(neigh->neighbor_sd); + r = nm_lldp_neighbor_tlv_rewind(neigh->neighbor_nm); if (r < 0) nm_assert_not_reached(); else { @@ -556,14 +486,14 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) guint8 type; guint8 subtype; - if (sd_lldp_neighbor_tlv_get_type(neigh->neighbor_sd, &type) < 0) + if (nm_lldp_neighbor_tlv_get_type(neigh->neighbor_nm, &type) < 0) continue; - if (sd_lldp_neighbor_tlv_get_raw(neigh->neighbor_sd, (void *) &data8, &len) < 0) + if (nm_lldp_neighbor_tlv_get_raw(neigh->neighbor_nm, (void *) &data8, &len) < 0) continue; switch (type) { - case SD_LLDP_TYPE_MGMT_ADDRESS: + case NM_LLDP_TYPE_MGMT_ADDRESS: tmp_variant = parse_management_address_tlv(data8, len); if (tmp_variant) { if (!v_management_addresses_has) { @@ -573,13 +503,13 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_builder_add_value(&v_management_addresses, tmp_variant); } continue; - case SD_LLDP_TYPE_PRIVATE: + case NM_LLDP_TYPE_PRIVATE: break; default: continue; } - r = sd_lldp_neighbor_tlv_get_oui(neigh->neighbor_sd, oui, &subtype); + r = nm_lldp_neighbor_tlv_get_oui(neigh->neighbor_nm, oui, &subtype); if (r < 0) { if (r == -ENXIO) continue; @@ -609,15 +539,15 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) data8 += 6; len -= 6; - if (memcmp(oui, SD_LLDP_OUI_802_1, sizeof(oui)) == 0) { + if (memcmp(oui, NM_LLDP_OUI_802_1, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: + case NM_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: if (len != 2) continue; if (!v_ieee_802_1_pvid) v_ieee_802_1_pvid = g_variant_new_uint32(unaligned_read_be16(data8)); break; - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: + case NM_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: if (len != 3) continue; if (!v_ieee_802_1_ppvid) { @@ -633,7 +563,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_builder_add_value(&v_ieee_802_1_ppvids, g_variant_builder_end(&tmp_builder)); break; - case SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: + case NM_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: { gs_free char *name_to_free = NULL; const char *name; @@ -669,9 +599,9 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) default: continue; } - } else if (memcmp(oui, SD_LLDP_OUI_802_3, sizeof(oui)) == 0) { + } else if (memcmp(oui, NM_LLDP_OUI_802_3, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: + case NM_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: if (len != 5) continue; @@ -687,7 +617,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) v_ieee_802_3_mac_phy_conf = g_variant_builder_end(&tmp_builder); } break; - case SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: + case NM_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: if (len != 3) continue; @@ -703,7 +633,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) v_ieee_802_3_power_via_mdi = g_variant_builder_end(&tmp_builder); } break; - case SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: + case NM_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: if (len != 2) continue; if (!v_ieee_802_3_max_frame_size) @@ -711,9 +641,9 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) g_variant_new_uint32(unaligned_read_be16(data8)); break; } - } else if (memcmp(oui, SD_LLDP_OUI_IANA, sizeof(oui)) == 0) { + } else if (memcmp(oui, NM_LLDP_OUI_IANA, sizeof(oui)) == 0) { switch (subtype) { - case SD_LLDP_OUI_IANA_SUBTYPE_MUD: + case NM_LLDP_OUI_IANA_SUBTYPE_MUD: if (!v_mud_url) { gs_free char *s_free = NULL; const char *s; @@ -725,7 +655,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) break; } } - } while (sd_lldp_neighbor_tlv_next(neigh->neighbor_sd) > 0); + } while (nm_lldp_neighbor_tlv_next(neigh->neighbor_nm) > 0); if (v_management_addresses_has) nm_g_variant_builder_add_sv(&builder, @@ -777,18 +707,17 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) GVariant * nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) { - nm_auto(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *neighbor_sd = NULL; - nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; - GVariant *variant; - int r; + nm_auto(nm_lldp_neighbor_unrefp) NMLldpNeighbor *neighbor_nm = NULL; + nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; + GVariant *variant; g_assert(raw_data); g_assert(raw_len > 0); - r = sd_lldp_neighbor_from_raw(&neighbor_sd, raw_data, raw_len); - g_assert(r >= 0); + neighbor_nm = nm_lldp_neighbor_new_from_raw(raw_data, raw_len); + g_assert(neighbor_nm); - neigh = lldp_neighbor_new(neighbor_sd); + neigh = lldp_neighbor_new(neighbor_nm); g_assert(neigh); variant = lldp_neighbor_to_variant(neigh); @@ -843,18 +772,18 @@ data_changed_schedule(NMLldpListener *self) } static void -process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean remove) +process_lldp_neighbor(NMLldpListener *self, NMLldpNeighbor *neighbor_nm, gboolean remove) { nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; LldpNeighbor *neigh_old; nm_assert(self); - nm_assert(self->lldp_handle); + nm_assert(self->lldp_rx); nm_assert(self->lldp_neighbors); - g_return_if_fail(neighbor_sd); + g_return_if_fail(neighbor_nm); - neigh = lldp_neighbor_new(neighbor_sd); + neigh = lldp_neighbor_new(neighbor_nm); if (!neigh) { _LOGT("process: failed to parse neighbor"); return; @@ -884,14 +813,17 @@ handle_changed: } static void -lldp_event_handler(sd_lldp_rx *lldp, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata) +lldp_event_handler(NMLldpRX *lldp, NMLldpRXEvent event, NMLldpNeighbor *n, void *user_data) { - process_lldp_neighbor(userdata, + NMLldpListener *self = user_data; + + _LOGD("event: %s", nm_lldp_rx_event_to_string(event)); + process_lldp_neighbor(self, n, !NM_IN_SET(event, - SD_LLDP_RX_EVENT_ADDED, - SD_LLDP_RX_EVENT_UPDATED, - SD_LLDP_RX_EVENT_REFRESHED)); + NM_LLDP_RX_EVENT_ADDED, + NM_LLDP_RX_EVENT_UPDATED, + NM_LLDP_RX_EVENT_REFRESHED)); } /*****************************************************************************/ @@ -935,35 +867,14 @@ nm_lldp_listener_new(int ifindex, gpointer notify_user_data, GError **error) { - NMLldpListener *self = NULL; - sd_lldp_rx *lldp_handle; - int r; + NMLldpListener *self = NULL; + nm_auto(nm_lldp_rx_unrefp) NMLldpRX *lldp_rx = NULL; + int r; g_return_val_if_fail(ifindex > 0, FALSE); g_return_val_if_fail(!error || !*error, FALSE); g_return_val_if_fail(notify_callback, FALSE); - r = sd_lldp_rx_new(&lldp_handle); - if (r < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "initialization failed"); - return FALSE; - } - - r = sd_lldp_rx_set_ifindex(lldp_handle, ifindex); - if (r < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed setting ifindex"); - goto fail_handle; - } - - r = sd_lldp_rx_set_neighbors_max(lldp_handle, MAX_NEIGHBORS); - nm_assert(r == 0); - self = g_slice_new(NMLldpListener); *self = (NMLldpListener){ .ifindex = ifindex, @@ -971,39 +882,33 @@ nm_lldp_listener_new(int ifindex, .notify_user_data = notify_user_data, }; - r = sd_lldp_rx_set_callback(lldp_handle, lldp_event_handler, self); - if (r < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed"); - goto fail_handle; - } + nm_assert(nm_g_main_context_is_thread_default(g_main_context_default())); - r = sd_lldp_rx_attach_event(lldp_handle, NULL, 0); - if (r < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "attach event failed"); - goto fail_attached; - } + lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig){ + .ifindex = ifindex, + .neighbors_max = MAX_NEIGHBORS, + .callback = lldp_event_handler, + .userdata = self, + })); - r = sd_lldp_rx_start(lldp_handle); + r = nm_lldp_rx_start(lldp_rx); if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "start failed"); - goto fail_attached; + goto fail; } - self->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash, - lldp_neighbor_id_equal, + self->lldp_neighbors = g_hash_table_new_full((GHashFunc) lldp_neighbor_id_hash, + (GEqualFunc) lldp_neighbor_id_equal, (GDestroyNotify) lldp_neighbor_free, NULL); - self->lldp_handle = lldp_handle; + + self->lldp_rx = g_steal_pointer(&lldp_rx); _LOGD("start lldp listener"); return self; -fail_attached: - sd_lldp_rx_detach_event(lldp_handle); -fail_handle: - if (self) - nm_g_slice_free(self); - sd_lldp_rx_unref(lldp_handle); +fail: + nm_g_slice_free(self); return NULL; } @@ -1012,9 +917,8 @@ nm_lldp_listener_destroy(NMLldpListener *self) { g_return_if_fail(self); - sd_lldp_rx_stop(self->lldp_handle); - sd_lldp_rx_detach_event(self->lldp_handle); - sd_lldp_rx_unref(self->lldp_handle); + nm_lldp_rx_stop(self->lldp_rx); + nm_lldp_rx_unref(self->lldp_rx); nm_clear_g_source_inst(&self->ratelimit_source); diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 048afb02..7b319af3 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -16,6 +16,7 @@ #include "nm-setting-connection.h" #include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge @@ -124,13 +125,14 @@ nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnec device_type = NM_DEVICE_TYPE_OVS_BRIDGE; } - nm_ovsdb_set_external_ids( - nm_ovsdb_get(), - device_type, - nm_device_get_ip_iface(self), - nm_connection_get_uuid(con_new), - _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), - _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS)); + nm_ovsdb_set_reapply(nm_ovsdb_get(), + device_type, + nm_device_get_ip_iface(self), + nm_connection_get_uuid(con_new), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), + _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_OTHER_CONFIG), + _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.h b/src/core/devices/ovs/nm-device-ovs-bridge.h index 2b893343..51cc685d 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.h +++ b/src/core/devices/ovs/nm-device-ovs-bridge.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type()) #define NM_DEVICE_OVS_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) #define NM_DEVICE_OVS_BRIDGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) #define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) diff --git a/src/core/devices/ovs/nm-device-ovs-interface.h b/src/core/devices/ovs/nm-device-ovs-interface.h index 03b0e9a4..b8c951d2 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.h +++ b/src/core/devices/ovs/nm-device-ovs-interface.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type()) #define NM_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) #define NM_DEVICE_OVS_INTERFACE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) #define NM_IS_DEVICE_OVS_INTERFACE(obj) \ diff --git a/src/core/devices/ovs/nm-device-ovs-port.h b/src/core/devices/ovs/nm-device-ovs-port.h index f4516c01..87446fa4 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.h +++ b/src/core/devices/ovs/nm-device-ovs-port.h @@ -8,7 +8,7 @@ #define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type()) #define NM_DEVICE_OVS_PORT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) #define NM_DEVICE_OVS_PORT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) #define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_PORT)) diff --git a/src/core/devices/ovs/nm-ovs-factory.c b/src/core/devices/ovs/nm-ovs-factory.c index ff2c7858..50023778 100644 --- a/src/core/devices/ovs/nm-ovs-factory.c +++ b/src/core/devices/ovs/nm-ovs-factory.c @@ -27,7 +27,8 @@ typedef struct { } NMOvsFactoryClass; #define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type()) -#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) +#define NM_OVS_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) #define NM_OVS_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) #define NM_IS_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVS_FACTORY)) diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 0d688396..85b7953f 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -17,6 +17,7 @@ #include "devices/nm-device.h" #include "nm-manager.h" #include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-other-config.h" #include "nm-priv-helper-call.h" #include "libnm-platform/nm-platform.h" @@ -24,18 +25,26 @@ #define OVSDB_MAX_FAILURES 3 +#define OTHER_CONFIG_HWADDR "hwaddr" + /*****************************************************************************/ #if JANSSON_VERSION_HEX < 0x020400 #warning "requires at least libjansson 2.4" #endif +typedef enum { + STRDICT_TYPE_EXTERNAL_IDS, + STRDICT_TYPE_OTHER_CONFIG, +} StrdictType; + typedef struct { char *port_uuid; char *name; char *connection_uuid; GPtrArray *interfaces; /* interface uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchPort; typedef struct { @@ -44,6 +53,7 @@ typedef struct { char *connection_uuid; GPtrArray *ports; /* port uuids */ GArray *external_ids; + GArray *other_config; } OpenvswitchBridge; typedef struct { @@ -52,6 +62,7 @@ typedef struct { char *type; char *connection_uuid; GArray *external_ids; + GArray *other_config; } OpenvswitchInterface; /*****************************************************************************/ @@ -66,7 +77,7 @@ typedef enum { OVSDB_ADD_INTERFACE, OVSDB_DEL_INTERFACE, OVSDB_SET_INTERFACE_MTU, - OVSDB_SET_EXTERNAL_IDS, + OVSDB_SET_REAPPLY, } OvsdbCommand; #define CALL_ID_UNSPEC G_MAXUINT64 @@ -92,9 +103,11 @@ typedef union { NMDeviceType device_type; char *ifname; char *connection_uuid; - GHashTable *exid_old; - GHashTable *exid_new; - } set_external_ids; + GHashTable *external_ids_old; + GHashTable *external_ids_new; + GHashTable *other_config_old; + GHashTable *other_config_new; + } set_reapply; } OvsdbMethodPayload; typedef struct { @@ -223,20 +236,24 @@ static void cleanup_check_ready(NMOvsdb *self); }, \ })) -#define OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(xdevice_type, \ - xifname, \ - xconnection_uuid, \ - xexid_old, \ - xexid_new) \ - (&((const OvsdbMethodPayload){ \ - .set_external_ids = \ - { \ - .device_type = xdevice_type, \ - .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ - .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ - .exid_old = (xexid_old), \ - .exid_new = (xexid_new), \ - }, \ +#define OVSDB_METHOD_PAYLOAD_SET_REAPPLY(xdevice_type, \ + xifname, \ + xconnection_uuid, \ + xexternal_ids_old, \ + xexternal_ids_new, \ + xother_config_old, \ + xother_config_new) \ + (&((const OvsdbMethodPayload){ \ + .set_reapply = \ + { \ + .device_type = xdevice_type, \ + .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ + .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ + .external_ids_old = (xexternal_ids_old), \ + .external_ids_new = (xexternal_ids_new), \ + .other_config_old = (xother_config_old), \ + .other_config_new = (xother_config_new), \ + }, \ })) /*****************************************************************************/ @@ -291,11 +308,13 @@ _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) case OVSDB_SET_INTERFACE_MTU: nm_clear_g_free(&call->payload.set_interface_mtu.ifname); break; - case OVSDB_SET_EXTERNAL_IDS: - nm_clear_g_free(&call->payload.set_external_ids.ifname); - nm_clear_g_free(&call->payload.set_external_ids.connection_uuid); - nm_clear_pointer(&call->payload.set_external_ids.exid_old, g_hash_table_destroy); - nm_clear_pointer(&call->payload.set_external_ids.exid_new, g_hash_table_destroy); + case OVSDB_SET_REAPPLY: + nm_clear_g_free(&call->payload.set_reapply.ifname); + nm_clear_g_free(&call->payload.set_reapply.connection_uuid); + nm_clear_pointer(&call->payload.set_reapply.external_ids_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.external_ids_new, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_old, g_hash_table_destroy); + nm_clear_pointer(&call->payload.set_reapply.other_config_new, g_hash_table_destroy); break; } @@ -312,6 +331,7 @@ _free_bridge(OpenvswitchBridge *ovs_bridge) g_free(ovs_bridge->connection_uuid); g_ptr_array_free(ovs_bridge->ports, TRUE); nm_g_array_unref(ovs_bridge->external_ids); + nm_g_array_unref(ovs_bridge->other_config); nm_g_slice_free(ovs_bridge); } @@ -323,6 +343,7 @@ _free_port(OpenvswitchPort *ovs_port) g_free(ovs_port->connection_uuid); g_ptr_array_free(ovs_port->interfaces, TRUE); nm_g_array_unref(ovs_port->external_ids); + nm_g_array_unref(ovs_port->other_config); nm_g_slice_free(ovs_port); } @@ -334,6 +355,7 @@ _free_interface(OpenvswitchInterface *ovs_interface) g_free(ovs_interface->connection_uuid); g_free(ovs_interface->type); nm_g_array_unref(ovs_interface->external_ids); + nm_g_array_unref(ovs_interface->other_config); nm_g_slice_free(ovs_interface); } @@ -447,19 +469,22 @@ ovsdb_call_method(NMOvsdb *self, call->payload.set_interface_mtu.ifname, call->payload.set_interface_mtu.mtu); break; - case OVSDB_SET_EXTERNAL_IDS: - call->payload.set_external_ids.device_type = payload->set_external_ids.device_type; - call->payload.set_external_ids.ifname = g_strdup(payload->set_external_ids.ifname); - call->payload.set_external_ids.connection_uuid = - g_strdup(payload->set_external_ids.connection_uuid); - call->payload.set_external_ids.exid_old = - nm_g_hash_table_ref(payload->set_external_ids.exid_old); - call->payload.set_external_ids.exid_new = - nm_g_hash_table_ref(payload->set_external_ids.exid_new); + case OVSDB_SET_REAPPLY: + call->payload.set_reapply.device_type = payload->set_reapply.device_type; + call->payload.set_reapply.ifname = g_strdup(payload->set_reapply.ifname); + call->payload.set_reapply.connection_uuid = g_strdup(payload->set_reapply.connection_uuid); + call->payload.set_reapply.external_ids_old = + nm_g_hash_table_ref(payload->set_reapply.external_ids_old); + call->payload.set_reapply.external_ids_new = + nm_g_hash_table_ref(payload->set_reapply.external_ids_new); + call->payload.set_reapply.other_config_old = + nm_g_hash_table_ref(payload->set_reapply.other_config_old); + call->payload.set_reapply.other_config_new = + nm_g_hash_table_ref(payload->set_reapply.other_config_new); _LOGT_call(call, - "new: set-external-ids con-uuid=%s, interface=%s", - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.ifname); + "new: set external-ids/other-config con-uuid=%s, interface=%s", + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.ifname); break; } @@ -604,12 +629,12 @@ _set_bridge_mac(json_t *params, const char *ifname, const char *mac) "other_config", "delete", "set", - "hwaddr", + OTHER_CONFIG_HWADDR, "other_config", "insert", "map", - "hwaddr", + OTHER_CONFIG_HWADDR, mac, "where", @@ -677,92 +702,155 @@ _set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) } static json_t * -_j_create_external_ids_array_new(NMConnection *connection) +_j_create_strdict_new(NMConnection *connection, + StrdictType strdict_type, + const char *other_config_hwaddr) { + NMSettingOvsOtherConfig *s_other_config = NULL; + NMSettingOvsExternalIDs *s_external_ids = NULL; json_t *array; - const char *const *external_ids = NULL; - guint n_external_ids = 0; + const char *const *strv = NULL; + guint n_strv = 0; guint i; const char *uuid; - NMSettingOvsExternalIDs *s_exid; nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); array = json_array(); - uuid = nm_connection_get_uuid(connection); - nm_assert(uuid); - json_array_append_new(array, json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + uuid = nm_connection_get_uuid(connection); + nm_assert(uuid); + json_array_append_new(array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, uuid)); + } else { + if (other_config_hwaddr) { + json_array_append_new(array, + json_pack("[s, s]", OTHER_CONFIG_HWADDR, other_config_hwaddr)); + } + } + + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + s_external_ids = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); + if (s_external_ids) + strv = nm_setting_ovs_external_ids_get_data_keys(s_external_ids, &n_strv); + } else { + s_other_config = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_OTHER_CONFIG); + if (s_other_config) + strv = nm_setting_ovs_other_config_get_data_keys(s_other_config, &n_strv); + } + + for (i = 0; i < n_strv; i++) { + const char *k = strv[i]; - s_exid = _nm_connection_get_setting(connection, NM_TYPE_SETTING_OVS_EXTERNAL_IDS); - if (s_exid) - external_ids = nm_setting_ovs_external_ids_get_data_keys(s_exid, &n_external_ids); - for (i = 0; i < n_external_ids; i++) { - const char *k = external_ids[i]; + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && other_config_hwaddr + && nm_streq(k, OTHER_CONFIG_HWADDR)) { + /* "hwaddr" is explicitly overwritten. */ + continue; + } json_array_append_new( array, - json_pack("[s, s]", k, nm_setting_ovs_external_ids_get_data(s_exid, k))); + json_pack("[s, s]", + k, + strdict_type == STRDICT_TYPE_EXTERNAL_IDS + ? nm_setting_ovs_external_ids_get_data(s_external_ids, k) + : nm_setting_ovs_other_config_get_data(s_other_config, k))); } return json_pack("[s, o]", "map", array); } -static json_t * -_j_create_external_ids_array_update(const char *connection_uuid, - GHashTable *exid_old, - GHashTable *exid_new) +static void +_j_create_strv_array_update(json_t *mutations, + StrdictType strdict_type, + const char *connection_uuid, + GHashTable *hash_old, + GHashTable *hash_new) { GHashTableIter iter; - json_t *mutations; json_t *array; const char *key; const char *val; - nm_assert(connection_uuid); + /* This is called during reapply. We accept reapplying all settings, + * except other_config:hwaddr. That one cannot change and is specially + * handled below. The reason is that we knew the correct "hwaddr" during + * _j_create_strdict_new(), but we don't do now. At least not easily, + * and it's not clear that reapply of the MAC address is really useful. */ - mutations = json_array(); + nm_assert((!!connection_uuid) == (strdict_type == STRDICT_TYPE_EXTERNAL_IDS)); + nm_assert(NM_IN_SET(strdict_type, STRDICT_TYPE_EXTERNAL_IDS, STRDICT_TYPE_OTHER_CONFIG)); - array = json_array(); - if (exid_old) { - g_hash_table_iter_init(&iter, exid_old); + array = NULL; + if (hash_old) { + g_hash_table_iter_init(&iter, hash_old); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) + continue; + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) { - if (nm_g_hash_table_contains(exid_old, key)) + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) continue; + if (nm_g_hash_table_contains(hash_old, key)) + continue; + if (!array) + array = json_array(); json_array_append_new(array, json_string(key)); } } - if (!nm_g_hash_table_contains(exid_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) - && !nm_g_hash_table_contains(exid_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { - json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (!nm_g_hash_table_contains(hash_old, NM_OVS_EXTERNAL_ID_NM_PREFIX) + && !nm_g_hash_table_contains(hash_new, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + if (!array) + array = json_array(); + json_array_append_new(array, json_string(NM_OVS_EXTERNAL_ID_NM_PREFIX)); + } + } + if (array) { + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "delete", + "set", + array)); } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "delete", "set", array)); array = json_array(); - json_array_append_new( - array, - json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); - - if (exid_new) { - g_hash_table_iter_init(&iter, exid_new); + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + json_array_append_new( + array, + json_pack("[s, s]", NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID, connection_uuid)); + } + if (hash_new) { + g_hash_table_iter_init(&iter, hash_new); while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { - if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) + if (strdict_type == STRDICT_TYPE_EXTERNAL_IDS) { + if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) + continue; + } + if (strdict_type == STRDICT_TYPE_OTHER_CONFIG && nm_streq(key, OTHER_CONFIG_HWADDR)) continue; json_array_append_new(array, json_pack("[s, s]", key, val)); } } - json_array_append_new(mutations, - json_pack("[s, s, [s, o]]", "external_ids", "insert", "map", array)); - return mutations; + json_array_append_new( + mutations, + json_pack("[s, s, [s, o]]", + strdict_type == STRDICT_TYPE_EXTERNAL_IDS ? "external_ids" : "other_config", + "insert", + "map", + array)); } /** @@ -779,18 +867,19 @@ _insert_interface(json_t *params, const char *type = NULL; NMSettingOvsInterface *s_ovs_iface; NMSettingOvsDpdk *s_ovs_dpdk; - const char *devargs; - guint32 n_rxq; char sbuf[64]; json_t *dpdk_array; NMSettingOvsPatch *s_ovs_patch; json_t *options = json_array(); json_t *row; - guint32 mtu = 0; + guint32 mtu = 0; + guint32 ofport_request = 0; s_ovs_iface = nm_connection_get_setting_ovs_interface(interface); - if (s_ovs_iface) - type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); + if (s_ovs_iface) { + type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); + ofport_request = nm_setting_ovs_interface_get_ofport_request(s_ovs_iface); + } if (nm_streq0(type, "internal")) { NMSettingWired *s_wired; @@ -808,8 +897,15 @@ _insert_interface(json_t *params, s_ovs_patch = nm_connection_get_setting_ovs_patch(interface); if (s_ovs_dpdk) { - devargs = nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk); - n_rxq = nm_setting_ovs_dpdk_get_n_rxq(s_ovs_dpdk); + const char *devargs; + guint32 n_rxq; + guint32 n_rxq_desc; + guint32 n_txq_desc; + + devargs = nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk); + n_rxq = nm_setting_ovs_dpdk_get_n_rxq(s_ovs_dpdk); + n_rxq_desc = nm_setting_ovs_dpdk_get_n_rxq_desc(s_ovs_dpdk); + n_txq_desc = nm_setting_ovs_dpdk_get_n_txq_desc(s_ovs_dpdk); dpdk_array = json_array(); @@ -820,6 +916,16 @@ _insert_interface(json_t *params, json_array_append_new(dpdk_array, json_pack("[s,s]", "n_rxq", nm_sprintf_buf(sbuf, "%u", n_rxq))); } + if (n_rxq_desc != 0) { + json_array_append_new( + dpdk_array, + json_pack("[s,s]", "n_rxq_desc", nm_sprintf_buf(sbuf, "%u", n_rxq_desc))); + } + if (n_txq_desc != 0) { + json_array_append_new( + dpdk_array, + json_pack("[s,s]", "n_txq_desc", nm_sprintf_buf(sbuf, "%u", n_txq_desc))); + } json_array_append_new(options, dpdk_array); @@ -831,7 +937,7 @@ _insert_interface(json_t *params, json_array_append_new(options, json_array()); } - row = json_pack("{s:s, s:s, s:o, s:o}", + row = json_pack("{s:s, s:s, s:o, s:o, s:o}", "name", nm_connection_get_interface_name(interface), "type", @@ -839,7 +945,9 @@ _insert_interface(json_t *params, "options", options, "external_ids", - _j_create_external_ids_array_new(interface)); + _j_create_strdict_new(interface, STRDICT_TYPE_EXTERNAL_IDS, NULL), + "other_config", + _j_create_strdict_new(interface, STRDICT_TYPE_OTHER_CONFIG, NULL)); if (cloned_mac) json_object_set_new(row, "mac", json_string(cloned_mac)); @@ -847,6 +955,9 @@ _insert_interface(json_t *params, if (mtu != 0) json_object_set_new(row, "mtu_request", json_integer(mtu)); + if (ofport_request != 0) + json_object_set_new(row, "ofport_request", json_integer(ofport_request)); + json_array_append_new(params, json_pack("{s:s, s:s, s:o, s:s}", "op", @@ -869,6 +980,7 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) { NMSettingOvsPort *s_ovs_port; const char *vlan_mode = NULL; + json_t *trunks = NULL; guint tag = 0; const char *lacp = NULL; const char *bond_mode = NULL; @@ -881,18 +993,34 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) row = json_object(); if (s_ovs_port) { + const GPtrArray *ranges; + guint i; + guint64 start; + guint64 end; + vlan_mode = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); tag = nm_setting_ovs_port_get_tag(s_ovs_port); lacp = nm_setting_ovs_port_get_lacp(s_ovs_port); bond_mode = nm_setting_ovs_port_get_bond_mode(s_ovs_port); bond_updelay = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); bond_downdelay = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); + + ranges = _nm_setting_ovs_port_get_trunks_arr(s_ovs_port); + for (i = 0; i < ranges->len; i++) { + if (!trunks) + trunks = json_array(); + nm_range_get_range(ranges->pdata[i], &start, &end); + for (; start <= end; start++) + json_array_append_new(trunks, json_integer(start)); + } } if (vlan_mode) json_object_set_new(row, "vlan_mode", json_string(vlan_mode)); if (tag) json_object_set_new(row, "tag", json_integer(tag)); + if (trunks) + json_object_set_new(row, "trunks", json_pack("[s, o]", "set", trunks)); if (lacp) json_object_set_new(row, "lacp", json_string(lacp)); if (bond_mode) @@ -904,7 +1032,12 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(port)); + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(port, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(port, STRDICT_TYPE_OTHER_CONFIG, NULL)); /* Create a new one. */ json_array_append_new(params, @@ -964,13 +1097,12 @@ _insert_bridge(json_t *params, json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(bridge))); json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); - json_object_set_new(row, "external_ids", _j_create_external_ids_array_new(bridge)); - - if (cloned_mac) { - json_object_set_new(row, - "other_config", - json_pack("[s, [[s, s]]]", "map", "hwaddr", cloned_mac)); - } + json_object_set_new(row, + "external_ids", + _j_create_strdict_new(bridge, STRDICT_TYPE_EXTERNAL_IDS, NULL)); + json_object_set_new(row, + "other_config", + _j_create_strdict_new(bridge, STRDICT_TYPE_OTHER_CONFIG, cloned_mac)); /* Create a new one. */ json_array_append_new(params, @@ -1332,9 +1464,9 @@ ovsdb_next_command(NMOvsdb *self) switch (call->command) { case OVSDB_MONITOR: msg = json_pack("{s:I, s:s, s:[s, n, {" - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s]}]," " s:[{s:[s, s, s, s]}]," + " s:[{s:[s, s, s, s]}]," + " s:[{s:[s, s, s, s, s]}]," " s:[{s:[]}]" "}]}", "id", @@ -1348,16 +1480,19 @@ ovsdb_next_command(NMOvsdb *self) "name", "ports", "external_ids", + "other_config", "Port", "columns", "name", "interfaces", "external_ids", + "other_config", "Interface", "columns", "name", "type", "external_ids", + "other_config", "error", "Open_vSwitch", "columns"); @@ -1398,24 +1533,38 @@ ovsdb_next_command(NMOvsdb *self) "==", call->payload.set_interface_mtu.ifname)); break; - case OVSDB_SET_EXTERNAL_IDS: + case OVSDB_SET_REAPPLY: + { + json_t *mutations; + + mutations = json_array(); + + _j_create_strv_array_update(mutations, + STRDICT_TYPE_EXTERNAL_IDS, + call->payload.set_reapply.connection_uuid, + call->payload.set_reapply.external_ids_old, + call->payload.set_reapply.external_ids_new); + _j_create_strv_array_update(mutations, + STRDICT_TYPE_OTHER_CONFIG, + NULL, + call->payload.set_reapply.other_config_old, + call->payload.set_reapply.other_config_new); + json_array_append_new( params, json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", "op", "mutate", "table", - _device_type_to_table(call->payload.set_external_ids.device_type), + _device_type_to_table(call->payload.set_reapply.device_type), "mutations", - _j_create_external_ids_array_update( - call->payload.set_external_ids.connection_uuid, - call->payload.set_external_ids.exid_old, - call->payload.set_external_ids.exid_new), + mutations, "where", "name", "==", - call->payload.set_external_ids.ifname)); + call->payload.set_reapply.ifname)); break; + } default: nm_assert_not_reached(); @@ -1500,19 +1649,18 @@ _uuids_to_array(const json_t *items) } static void -_external_ids_extract(json_t *external_ids, GArray **out_array, const char **out_connection_uuid) +_strdict_extract(json_t *strdict, GArray **out_array) { json_t *array; json_t *value; gsize index; nm_assert(out_array && !*out_array); - nm_assert(!out_connection_uuid || !*out_connection_uuid); - if (!nm_streq0("map", json_string_value(json_array_get(external_ids, 0)))) + if (!nm_streq0("map", json_string_value(json_array_get(strdict, 0)))) return; - array = json_array_get(external_ids, 1); + array = json_array_get(strdict, 1); json_array_foreach (array, index, value) { const char *key = json_string_value(json_array_get(value, 0)); @@ -1533,16 +1681,26 @@ _external_ids_extract(json_t *external_ids, GArray **out_array, const char **out .name = g_strdup(key), .value_str = g_strdup(val), }; - - if (out_connection_uuid && nm_streq(v->name, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID)) { - *out_connection_uuid = v->value_str; - out_connection_uuid = NULL; - } } } +static const char * +_strdict_find_key(GArray *array, const char *key) +{ + gssize idx; + + idx = nm_utils_named_value_list_find(nm_g_array_first_p(array, NMUtilsNamedValue), + nm_g_array_len(array), + key, + FALSE); + if (idx < 0) + return NULL; + + return nm_g_array_index(array, NMUtilsNamedValue, idx).value_str; +} + static gboolean -_external_ids_equal(const GArray *arr1, const GArray *arr2) +_strdict_equals(const GArray *arr1, const GArray *arr2) { guint n; guint i; @@ -1552,19 +1710,19 @@ _external_ids_equal(const GArray *arr1, const GArray *arr2) if (n != nm_g_array_len(arr2)) return FALSE; for (i = 0; i < n; i++) { - const NMUtilsNamedValue *n1 = &g_array_index(arr1, NMUtilsNamedValue, i); - const NMUtilsNamedValue *n2 = &g_array_index(arr2, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n1 = &nm_g_array_index(arr1, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n2 = &nm_g_array_index(arr2, NMUtilsNamedValue, i); - if (!nm_streq0(n1->name, n2->name)) + if (!nm_streq(n1->name, n2->name)) return FALSE; - if (!nm_streq0(n1->value_str, n2->value_str)) + if (!nm_streq(n1->value_str, n2->value_str)) return FALSE; } return TRUE; } static char * -_external_ids_to_string(const GArray *arr) +_strdict_to_string(const GArray *arr) { NMStrBuf strbuf; guint i; @@ -1575,7 +1733,7 @@ _external_ids_to_string(const GArray *arr) strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); nm_str_buf_append(&strbuf, "["); for (i = 0; i < arr->len; i++) { - const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i); + const NMUtilsNamedValue *n = &nm_g_array_index(arr, NMUtilsNamedValue, i); if (i > 0) nm_str_buf_append_c(&strbuf, ','); @@ -1605,8 +1763,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_t *interface = NULL; json_t *items; json_t *external_ids; + json_t *other_config; json_error_t json_error = { - 0, + 0, }; void *iter; const char *name; @@ -1644,12 +1803,13 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_object_foreach (interface, key, value) { OpenvswitchInterface *ovs_interface; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; json_t *error = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:s, s?:o, s:o}}", + "{s:{s:s, s:s, s?:o, s:o, s:o}}", "new", "name", &name, @@ -1658,7 +1818,9 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) "error", &error, "external_ids", - &external_ids); + &external_ids, + "other_config", + &other_config); if (r != 0) { gpointer unused; @@ -1701,7 +1863,10 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_interface, _free_interface); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); if (ovs_interface) { gboolean changed = FALSE; @@ -1710,14 +1875,20 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) changed |= nm_strdup_reset(&ovs_interface->type, type); changed |= nm_strdup_reset(&ovs_interface->connection_uuid, connection_uuid); - if (!_external_ids_equal(ovs_interface->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_interface->external_ids, external_ids_arr)) { NM_SWAP(&ovs_interface->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_interface->other_config, other_config_arr)) { + NM_SWAP(&ovs_interface->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s", + _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s, " + "other-config=%s", key, type, ovs_interface->name, @@ -1725,10 +1896,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) ", ", ovs_interface->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_interface = g_slice_new(OpenvswitchInterface); *ovs_interface = (OpenvswitchInterface){ @@ -1737,17 +1910,20 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .type = g_strdup(type), .connection_uuid = g_strdup(connection_uuid), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->interfaces, ovs_interface); - _LOGT("obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s", - key, - ovs_interface->type, - ovs_interface->name, - NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", - ovs_interface->connection_uuid, - ""), - (strtmp = _external_ids_to_string(ovs_interface->external_ids))); + _LOGT( + "obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s, other-config=%s", + key, + ovs_interface->type, + ovs_interface->name, + NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, + ", ", + ovs_interface->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -1768,16 +1944,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *interfaces = NULL; OpenvswitchPort *ovs_port; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "interfaces", &items); if (r != 0) { @@ -1811,7 +1990,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_port, _free_port); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); + interfaces = _uuids_to_array(items); if (ovs_port) { @@ -1825,24 +2008,31 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_port->interfaces, &interfaces); changed = TRUE; } - if (!_external_ids_equal(ovs_port->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_port->external_ids, external_ids_arr)) { NM_SWAP(&ovs_port->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_port->other_config, other_config_arr)) { + NM_SWAP(&ovs_port->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_port = g_slice_new(OpenvswitchPort); *ovs_port = (OpenvswitchPort){ @@ -1851,16 +2041,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .interfaces = g_steal_pointer(&interfaces), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->ports, ovs_port); - _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s", + _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s, other-config=%s", key, ovs_port->name, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, ", ", ovs_port->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_port->external_ids))); + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); _signal_emit_device_added(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); } } @@ -1869,16 +2061,19 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_unref_ptrarray GPtrArray *ports = NULL; OpenvswitchBridge *ovs_bridge; gs_unref_array GArray *external_ids_arr = NULL; + gs_unref_array GArray *other_config_arr = NULL; const char *connection_uuid = NULL; int r; r = json_unpack(value, - "{s:{s:s, s:o, s:o}}", + "{s:{s:s, s:o, s:o, s:o}}", "new", "name", &name, "external_ids", &external_ids, + "other_config", + &other_config, "ports", &items); @@ -1916,7 +2111,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) nm_clear_pointer(&ovs_bridge, _free_bridge); } - _external_ids_extract(external_ids, &external_ids_arr, &connection_uuid); + _strdict_extract(external_ids, &external_ids_arr); + connection_uuid = + _strdict_find_key(external_ids_arr, NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID); + _strdict_extract(other_config, &other_config_arr); + ports = _uuids_to_array(items); if (ovs_bridge) { @@ -1930,24 +2129,31 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) NM_SWAP(&ovs_bridge->ports, &ports); changed = TRUE; } - if (!_external_ids_equal(ovs_bridge->external_ids, external_ids_arr)) { + if (!_strdict_equals(ovs_bridge->external_ids, external_ids_arr)) { NM_SWAP(&ovs_bridge->external_ids, &external_ids_arr); changed = TRUE; } + if (!_strdict_equals(ovs_bridge->other_config, other_config_arr)) { + NM_SWAP(&ovs_bridge->other_config, &other_config_arr); + changed = TRUE; + } if (changed) { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; - _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->external_ids))); } } else { - gs_free char *strtmp = NULL; + gs_free char *strtmp1 = NULL; + gs_free char *strtmp2 = NULL; ovs_bridge = g_slice_new(OpenvswitchBridge); *ovs_bridge = (OpenvswitchBridge){ @@ -1956,16 +2162,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .connection_uuid = g_strdup(connection_uuid), .ports = g_steal_pointer(&ports), .external_ids = g_steal_pointer(&external_ids_arr), + .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->bridges, ovs_bridge); - _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s", + _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s, other-config=%s", key, ovs_bridge->name, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, ", ", ovs_bridge->connection_uuid, ""), - (strtmp = _external_ids_to_string(ovs_bridge->external_ids))); + (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), + (strtmp2 = _strdict_to_string(ovs_bridge->other_config))); _signal_emit_device_added(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); } } @@ -2007,7 +2215,7 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); json_error_t json_error = { - 0, + 0, }; json_t *json_id = NULL; json_int_t id = (json_int_t) -1; @@ -2149,7 +2357,7 @@ ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) gssize size; json_t *msg; json_error_t json_error = { - 0, + 0, }; size = g_input_stream_read_finish(stream, res, &error); @@ -2703,31 +2911,50 @@ nm_ovsdb_set_interface_mtu(NMOvsdb *self, } void -nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - NMSettingOvsExternalIDs *s_exid_old, - NMSettingOvsExternalIDs *s_exid_new) +nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new) { - gs_unref_hashtable GHashTable *exid_old = NULL; - gs_unref_hashtable GHashTable *exid_new = NULL; - - exid_old = - s_exid_old ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_old)) : NULL; - exid_new = - s_exid_new ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_exid_new)) : NULL; + gs_unref_hashtable GHashTable *external_ids_old = NULL; + gs_unref_hashtable GHashTable *external_ids_new = NULL; + gs_unref_hashtable GHashTable *other_config_old = NULL; + gs_unref_hashtable GHashTable *other_config_new = NULL; + + external_ids_old = + s_external_ids_old + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_old)) + : NULL; + external_ids_new = + s_external_ids_new + ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_new)) + : NULL; + + other_config_old = + s_other_config_old + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_old)) + : NULL; + other_config_new = + s_other_config_new + ? nm_strdict_clone(_nm_setting_ovs_other_config_get_data(s_other_config_new)) + : NULL; ovsdb_call_method(self, NULL, NULL, FALSE, - OVSDB_SET_EXTERNAL_IDS, - OVSDB_METHOD_PAYLOAD_SET_EXTERNAL_IDS(device_type, - ifname, - connection_uuid, - exid_old, - exid_new)); + OVSDB_SET_REAPPLY, + OVSDB_METHOD_PAYLOAD_SET_REAPPLY(device_type, + ifname, + connection_uuid, + external_ids_old, + external_ids_new, + other_config_old, + other_config_new)); } /*****************************************************************************/ diff --git a/src/core/devices/ovs/nm-ovsdb.h b/src/core/devices/ovs/nm-ovsdb.h index a50db45a..a022ff00 100644 --- a/src/core/devices/ovs/nm-ovsdb.h +++ b/src/core/devices/ovs/nm-ovsdb.h @@ -7,7 +7,7 @@ #define __NETWORKMANAGER_OVSDB_H__ #define NM_TYPE_OVSDB (nm_ovsdb_get_type()) -#define NM_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) +#define NM_OVSDB(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) #define NM_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVSDB, NMOvsdbClass)) #define NM_IS_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVSDB)) #define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVSDB)) @@ -47,14 +47,14 @@ void nm_ovsdb_set_interface_mtu(NMOvsdb *self, NMOvsdbCallback callback, gpointer user_data); -struct _NMSettingOvsExternalIDs; - -void nm_ovsdb_set_external_ids(NMOvsdb *self, - NMDeviceType device_type, - const char *ifname, - const char *connection_uuid, - struct _NMSettingOvsExternalIDs *s_exid_old, - struct _NMSettingOvsExternalIDs *s_exid_new); +void nm_ovsdb_set_reapply(NMOvsdb *self, + NMDeviceType device_type, + const char *ifname, + const char *connection_uuid, + NMSettingOvsExternalIDs *s_external_ids_old, + NMSettingOvsExternalIDs *s_external_ids_new, + NMSettingOvsOtherConfig *s_other_config_old, + NMSettingOvsOtherConfig *s_other_config_new); gboolean nm_ovsdb_is_ready(NMOvsdb *self); diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index 9eca008a..3e3fe52b 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -144,6 +144,7 @@ _update_port_config(NMDeviceTeam *self, const char *port_iface, const char *sani NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); int err; + _LOGT(LOGD_TEAM, "setting port config: %s", sanitized_config); err = teamdctl_port_config_update_raw(priv->tdc, port_iface, sanitized_config); if (err != 0) { _LOGE(LOGD_TEAM, "failed to update config for port %s (err=%d)", port_iface, err); @@ -154,23 +155,20 @@ _update_port_config(NMDeviceTeam *self, const char *port_iface, const char *sani } static gboolean -ensure_teamd_connection(NMDevice *device) +ensure_teamd_connection(NMDevice *device, GError **error) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - const char *port_iface; - const char *port_config; - GHashTableIter iter; + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + const char *port_iface; + const char *port_config; + GHashTableIter iter; if (priv->tdc) return TRUE; - priv->tdc = _tdc_connect_new(self, nm_device_get_iface(device), &error); - if (!priv->tdc) { - _LOGE(LOGD_TEAM, "failed to connect to teamd: %s", error->message); + priv->tdc = _tdc_connect_new(self, nm_device_get_iface(device), error); + if (!priv->tdc) return FALSE; - } g_hash_table_iter_init(&iter, priv->port_configs); while (g_hash_table_iter_next(&iter, (gpointer *) &port_iface, (gpointer *) &port_config)) @@ -229,10 +227,17 @@ update_connection(NMDevice *device, NMConnection *connection) NMSettingTeam *s_team = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_TEAM); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); struct teamdctl *tdc = priv->tdc; + GError *error = NULL; /* Read the configuration only if not already set */ - if (!priv->config && ensure_teamd_connection(device)) - teamd_read_config(self); + if (!priv->config) { + if (ensure_teamd_connection(device, &error)) { + teamd_read_config(self); + } else { + _LOGD(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); + } + } /* Restore previous tdc state */ if (priv->tdc && !tdc) { @@ -258,9 +263,10 @@ master_update_slave_connection(NMDevice *device, gs_free_error GError *connect_error = NULL; int err = 0; struct teamdctl *tdc; - const char *team_port_config = NULL; - const char *iface = nm_device_get_iface(device); - const char *iface_slave = nm_device_get_iface(slave); + const char *team_port_config = NULL; + const char *iface = nm_device_get_iface(device); + const char *iface_slave = nm_device_get_iface(slave); + NMConnection *applied_connection = nm_device_get_applied_connection(device); tdc = _tdc_connect_new(self, iface, &connect_error); if (!tdc) { @@ -299,7 +305,7 @@ master_update_slave_connection(NMDevice *device, g_object_set(nm_connection_get_setting_connection(connection), NM_SETTING_CONNECTION_MASTER, - iface, + nm_connection_get_uuid(applied_connection), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); @@ -397,6 +403,7 @@ teamd_ready(NMDeviceTeam *self) NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); NMDevice *device = NM_DEVICE(self); gboolean success; + GError *error = NULL; if (priv->kill_in_progress) { /* If we are currently killing teamd, we are not @@ -410,7 +417,11 @@ teamd_ready(NMDeviceTeam *self) * immediately. But if we are, and grabbing it failed, fail the * device activation. */ - success = ensure_teamd_connection(device); + success = ensure_teamd_connection(device, &error); + if (!success) { + _LOGW(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); + } if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) @@ -759,18 +770,20 @@ teamd_start(NMDeviceTeam *self) static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - NMSettingTeam *s_team; - const char *cfg; + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + GError *error = NULL; + NMSettingTeam *s_team; + const char *cfg; if (nm_device_sys_iface_state_is_external(device)) return NM_ACT_STAGE_RETURN_SUCCESS; if (nm_device_sys_iface_state_is_external_or_assume(device)) { - if (ensure_teamd_connection(device)) + if (ensure_teamd_connection(device, &error)) return NM_ACT_STAGE_RETURN_SUCCESS; + _LOGD(LOGD_TEAM, "could not connect to teamd: %s", error->message); + g_clear_error(&error); } s_team = nm_device_get_applied_setting(device, NM_TYPE_SETTING_TEAM); @@ -803,6 +816,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) _LOGW(LOGD_TEAM, "existing teamd config mismatch; failed to kill existing teamd: %s", error->message); + g_clear_error(&error); NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } diff --git a/src/core/devices/team/nm-device-team.h b/src/core/devices/team/nm-device-team.h index 6f5cff93..e2a54c6e 100644 --- a/src/core/devices/team/nm-device-team.h +++ b/src/core/devices/team/nm-device-team.h @@ -9,7 +9,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_TEAM (nm_device_team_get_type()) -#define NM_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam)) +#define NM_DEVICE_TEAM(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam)) #define NM_DEVICE_TEAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) #define NM_IS_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TEAM)) diff --git a/src/core/devices/team/nm-team-factory.c b/src/core/devices/team/nm-team-factory.c index b446cbd0..68ea914e 100644 --- a/src/core/devices/team/nm-team-factory.c +++ b/src/core/devices/team/nm-team-factory.c @@ -17,7 +17,7 @@ #define NM_TYPE_TEAM_FACTORY (nm_team_factory_get_type()) #define NM_TEAM_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) #define NM_TEAM_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_TEAM_FACTORY, NMTeamFactoryClass)) #define NM_IS_TEAM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_TEAM_FACTORY)) diff --git a/src/core/devices/tests/test-lldp.c b/src/core/devices/tests/test-lldp.c index 048410c1..4cd602f7 100644 --- a/src/core/devices/tests/test-lldp.c +++ b/src/core/devices/tests/test-lldp.c @@ -12,9 +12,8 @@ #include <sys/stat.h> #include <sys/types.h> +#include "libnm-lldp/nm-lldp.h" #include "devices/nm-lldp-listener.h" -#include "libnm-systemd-core/nm-sd.h" - #include "platform/tests/test-common.h" #include "nm-test-utils-core.h" @@ -191,9 +190,9 @@ _test_recv_data0_check_do(GMainLoop *loop, NMLldpListener *listener, const TestR g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, + NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:02:03:04:05", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, + NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/3"); g_assert(neighbor); g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 4); @@ -547,9 +546,9 @@ _test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallba g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, + NM_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, "00:01:30:F9:AD:A0", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, + NM_LLDP_PORT_SUBTYPE_INTERFACE_NAME, "1/1"); g_assert(neighbor); g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 16); @@ -874,7 +873,6 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) TestRecvCallbackInfo info = {}; gsize i_frames; GError *error = NULL; - guint sd_id; if (fixture->ifindex == 0) { g_test_skip("Tun device not available"); @@ -884,8 +882,7 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) listener = nm_lldp_listener_new(fixture->ifindex, lldp_neighbors_changed, &info, &error); nmtst_assert_success(listener, error); - loop = g_main_loop_new(NULL, FALSE); - sd_id = nm_sd_event_attach_default(); + loop = g_main_loop_new(NULL, FALSE); for (i_frames = 0; i_frames < data->frames_len; i_frames++) { const TestRecvFrame *f = data->frames[i_frames]; @@ -902,7 +899,6 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) nm_clear_pointer(&listener, nm_lldp_listener_destroy); - nm_clear_g_source(&sd_id); nm_clear_pointer(&loop, g_main_loop_unref); } diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.h b/src/core/devices/wifi/nm-device-iwd-p2p.h index 9ce353c0..98cf3762 100644 --- a/src/core/devices/wifi/nm-device-iwd-p2p.h +++ b/src/core/devices/wifi/nm-device-iwd-p2p.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_IWD_P2P (nm_device_iwd_p2p_get_type()) #define NM_DEVICE_IWD_P2P(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2P)) #define NM_DEVICE_IWD_P2P_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD_P2P, NMDeviceIwdP2PClass)) #define NM_IS_DEVICE_IWD_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD_P2P)) diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index ab37cbec..e03227cd 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -8,6 +8,7 @@ #include "nm-device-iwd.h" #include <linux/if_ether.h> +#include <linux/rtnetlink.h> #include "devices/nm-device-private.h" #include "devices/nm-device.h" @@ -32,6 +33,7 @@ #include "supplicant/nm-supplicant-types.h" #include "nm-auth-utils.h" #include "nm-manager.h" +#include "nm-l3-config-data.h" #define _NMLOG_DEVICE_TYPE NMDeviceIwd #include "devices/nm-device-logging.h" @@ -70,6 +72,7 @@ typedef struct { bool secrets_failed : 1; bool networks_requested : 1; bool networks_changed : 1; + bool assuming : 1; gint64 last_scan; uint32_t ap_id; guint32 rate; @@ -77,6 +80,16 @@ typedef struct { GDBusMethodInvocation *pending_agent_request; NMActiveConnection *assumed_ac; guint assumed_ac_timeout; + + union { + struct { + const NML3ConfigData *pending_l3cd_6; + const NML3ConfigData *pending_l3cd_4; + }; + const NML3ConfigData *pending_l3cd_x[2]; + }; + + NMIwdManager *manager; } NMDeviceIwdPrivate; struct _NMDeviceIwd { @@ -289,6 +302,7 @@ insert_ap_from_network(NMDeviceIwd *self, gint64 last_seen_msec, int16_t signal) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); gs_unref_object GDBusProxy *network_proxy = NULL; nm_auto_ref_string NMRefString *bss_path = nm_ref_string_new(path); NMWifiAP *ap; @@ -299,7 +313,7 @@ insert_ap_from_network(NMDeviceIwd *self, } network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE); + nm_iwd_manager_get_dbus_interface(priv->manager, path, NM_IWD_NETWORK_INTERFACE); ap = ap_from_network(self, network_proxy, bss_path, last_seen_msec, signal); if (!ap) @@ -525,6 +539,9 @@ cleanup_association_attempt(NMDeviceIwd *self, gboolean disconnect) if (disconnect && priv->dbus_station_proxy) send_disconnect(self); + + nm_clear_l3cd(&priv->pending_l3cd_6); + nm_clear_l3cd(&priv->pending_l3cd_4); } static void @@ -581,6 +598,10 @@ deactivate(NMDevice *device) if (!priv->dbus_obj) return; + /* Don't cause IWD to break the connection being assumed */ + if (priv->assuming) + return; + if (priv->dbus_station_proxy) { gs_unref_variant GVariant *value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State"); @@ -673,7 +694,7 @@ deactivate_async(NMDevice *device, } static gboolean -is_connection_known_network(NMConnection *connection) +is_connection_known_network(NMIwdManager *manager, NMConnection *connection) { NMIwdNetworkSecurity security; gs_free char *ssid = NULL; @@ -681,17 +702,17 @@ is_connection_known_network(NMConnection *connection) if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, &ssid, &security)) return FALSE; - return nm_iwd_manager_is_known_network(nm_iwd_manager_get(), ssid, security); + return nm_iwd_manager_is_known_network(manager, ssid, security); } static gboolean -is_ap_known_network(NMWifiAP *ap) +is_ap_known_network(NMIwdManager *manager, NMWifiAP *ap) { gs_unref_object GDBusProxy *network_proxy = NULL; gs_unref_variant GVariant *known_network = NULL; network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), + nm_iwd_manager_get_dbus_interface(manager, nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) @@ -794,7 +815,8 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * * thus are Known Networks. */ if (security == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network(connection)) { + if (!is_connection_known_network(priv->manager, connection) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, ssid)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "802.1x connections must have IWD provisioning files"); @@ -927,7 +949,9 @@ check_connection_available(NMDevice *device, */ if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) && security == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_ap_known_network(ap)) { + if (!is_ap_known_network(priv->manager, ap) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, + nm_setting_wireless_get_ssid(s_wifi))) { nm_utils_error_set_literal( error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, @@ -2044,7 +2068,7 @@ assume_connection(NMDeviceIwd *self, NMWifiAP *ap) * becomes "managed" only when ACTIVATED but for IWD it's really * managed when IP_CONFIG starts. */ - sett_conn = nm_iwd_manager_get_ap_mirror_connection(nm_iwd_manager_get(), ap); + sett_conn = nm_iwd_manager_get_ap_mirror_connection(priv->manager, ap); if (!sett_conn) goto error; @@ -2217,7 +2241,8 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) * for a first-time connection to a hidden network. If a hidden network is * a Known Network it should still have been in the AP list. */ - if (!nm_setting_wireless_get_hidden(s_wireless) || is_connection_known_network(connection)) + if (!nm_setting_wireless_get_hidden(s_wireless) + || is_connection_known_network(priv->manager, connection)) return NM_ACT_STAGE_RETURN_FAILURE; add_new: @@ -2270,6 +2295,18 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out_fail; } + /* With priv->iwd_autoconnect we have to let IWD handle retries for + * infrastructure networks. IWD will not necessarily retry the same + * network after a failure but it will likely go into an autoconnect + * mode and we don't want to try to override the logic. We don't need + * to reset the retry count so we set no timeout. + */ + if (priv->iwd_autoconnect) { + NMSettingsConnection *sett_conn = nm_act_request_get_settings_connection(req); + + nm_settings_connection_autoconnect_retries_set(sett_conn, 0); + } + /* With priv->iwd_autoconnect, if we're assuming a connection because * of a state change to "connecting", signal stage 2 is still running. * If "connected" or "roaming", we can go right to the IP_CONFIG state @@ -2310,7 +2347,9 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) * fail, for other combinations we will let the Connect call fail * or ask us for any missing secrets through the Agent. */ - if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(ap)) { + if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(priv->manager, ap) + && !nm_iwd_manager_is_recently_mirrored(priv->manager, + nm_setting_wireless_get_ssid(s_wireless))) { _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) access point '%s' has 802.1x security but is not configured " "in IWD.", @@ -2351,7 +2390,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) } network_proxy = nm_iwd_manager_get_dbus_interface( - nm_iwd_manager_get(), + priv->manager, nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { @@ -2421,6 +2460,38 @@ out_fail: return NM_ACT_STAGE_RETURN_FAILURE; } +static void +act_stage3_ip_config(NMDevice *device, int addr_family) +{ + NMDeviceIwd *self = NM_DEVICE_IWD(device); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + if (!nm_iwd_manager_get_netconfig_enabled(nm_iwd_manager_get())) { + NMDeviceClass *device_class = NM_DEVICE_CLASS(nm_device_iwd_parent_class); + + if (device_class->act_stage3_ip_config) + device_class->act_stage3_ip_config(device, addr_family); + + return; + } + + if (!priv->pending_l3cd_x[IS_IPv4]) + return; + + nm_device_devip_set_state(device, + addr_family, + NM_DEVICE_IP_STATE_READY, + priv->pending_l3cd_x[IS_IPv4]); + nm_clear_l3cd(&priv->pending_l3cd_x[IS_IPv4]); +} + +static gboolean +ready_for_ip_config(NMDevice *device, gboolean is_manual) +{ + return !nm_iwd_manager_get_netconfig_enabled(nm_iwd_manager_get()); +} + static guint32 get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) { @@ -2719,12 +2790,20 @@ state_changed(NMDeviceIwd *self, const char *new_state) "IWD is connecting to the wrong AP, %s activation", switch_ap ? "replacing" : "aborting"); cleanup_association_attempt(self, !switch_ap); + + if (!switch_ap) { + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + return; + } + + priv->assuming = TRUE; /* Don't send Station.Disconnect() */ nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - - if (switch_ap) - assume_connection(self, ap); + priv->assuming = FALSE; + assume_connection(self, ap); return; } @@ -3101,7 +3180,7 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) goto error; } - adapter_proxy = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), + adapter_proxy = nm_iwd_manager_get_dbus_interface(priv->manager, g_variant_get_string(value, NULL), NM_IWD_WIPHY_INTERFACE); if (!adapter_proxy) { @@ -3278,7 +3357,7 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) * it. IWD only queries us if it has not saved the PSK (e.g. by policy) * or a previous attempt has failed with current secrets so it wants a * fresh value. It doesn't know about agent-owned secrets so whenever - * possible and the PSK is saved and not asked from NM. However if this + * possible, the PSK is saved and not asked from NM. However if this * is a new connection it may include all of the needed settings already * so allow using these, too. Connection timestamp is set after * activation or after first activation failure (to 0). @@ -3368,6 +3447,341 @@ nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool ad } } +static const NML3ConfigData * +nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter *config_iter) +{ + NMDevice *device = NM_DEVICE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + const char *key; + GVariant *value; + NMIPConfigSource source = NM_IP_CONFIG_SOURCE_UNKNOWN; + nm_auto_free_variant_iter GVariantIter *address_iter = NULL; + nm_auto_free_variant_iter GVariantIter *route_iter = NULL; + nm_auto_free_variant_iter GVariantIter *dns_iter = NULL; + nm_auto_free_variant_iter GVariantIter *domain_iter = NULL; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + const char *str_value; + GVariantIter *entry_iter; + uint32_t timestamp = nm_utils_get_monotonic_timestamp_sec(); + + while (g_variant_iter_next(config_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Method")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) + || source != NM_IP_CONFIG_SOURCE_UNKNOWN) + goto param_error; + + str_value = g_variant_get_string(value, NULL); + if (nm_streq(str_value, "static")) + source = NM_IP_CONFIG_SOURCE_USER; + else if (nm_streq(str_value, "auto")) + /* Use SOURCE_DHCP as shorthand for the various autoconfiguration protocols */ + source = NM_IP_CONFIG_SOURCE_DHCP; + else + _LOGW(LOGD_WIFI, "iwd_parse_netconfig: Uknown Method value \"%s\"", str_value); + } + + if (nm_streq(key, "Addresses")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")) || address_iter) + goto param_error; + + g_variant_get(value, "aa{sv}", &address_iter); + } + + if (nm_streq(key, "Routes")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")) || route_iter) + goto param_error; + + g_variant_get(value, "aa{sv}", &route_iter); + } + + if (nm_streq(key, "DomainNameServers")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY) || dns_iter) + goto param_error; + + g_variant_get(value, "as", &dns_iter); + } + + if (nm_streq(key, "DomainNames")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY) || domain_iter) + goto param_error; + + g_variant_get(value, "as", &domain_iter); + } + + if (nm_streq(key, "MDNS")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) + || mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + goto param_error; + + str_value = g_variant_get_string(value, NULL); + if (nm_streq(str_value, "yes")) + mdns = NM_SETTING_CONNECTION_MDNS_YES; + else if (nm_streq(str_value, "no")) + mdns = NM_SETTING_CONNECTION_MDNS_NO; + else if (nm_streq(str_value, "resolve")) + mdns = NM_SETTING_CONNECTION_MDNS_RESOLVE; + else + _LOGW(LOGD_WIFI, "iwd_parse_netconfig: Uknown MDNS value \"%s\"", str_value); + } + } + + if (!address_iter || !route_iter) + goto param_error; + + l3cd = nm_l3_config_data_new(nm_device_get_multi_index(device), + nm_device_get_ip_ifindex(device), + source); + + while (g_variant_iter_next(address_iter, "a{sv}", &entry_iter)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *entry_iter_free = entry_iter; + const char *addr_str = NULL; + NMIPAddr addr_bin; + uint8_t plen = 0; + const char *bcast_str = NULL; + NMIPAddr bcast_bin = {}; + uint32_t valid_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + uint32_t preferred_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + NMPlatformIPXAddress a; + + while (g_variant_iter_next(entry_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Address")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || addr_str) + goto param_error; + + addr_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, addr_str, &addr_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "PrefixLength")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTE)) + goto param_error; + + plen = g_variant_get_byte(value); + } + + if (nm_streq(key, "Broadcast")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || bcast_str) + goto param_error; + + bcast_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, bcast_str, &bcast_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "ValidLifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + valid_lifetime = g_variant_get_uint32(value); + } + + if (nm_streq(key, "PreferredLifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || preferred_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + preferred_lifetime = g_variant_get_uint32(value); + } + } + + if (addr_str == NULL) + goto param_error; + + if (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT + && preferred_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) + preferred_lifetime = valid_lifetime; + + if (addr_family == AF_INET) { + a.a4 = (NMPlatformIP4Address){ + .address = addr_bin.addr4, + .peer_address = addr_bin.addr4, + .plen = plen, + .timestamp = (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) ? timestamp : 0, + .lifetime = valid_lifetime, + .preferred = preferred_lifetime, + .addr_source = source, + .use_ip4_broadcast_address = (bcast_str != NULL), + .broadcast_address = bcast_bin.addr4, + }; + } else { + a.a6 = (NMPlatformIP6Address){ + .address = addr_bin.addr6, + .plen = 128, + .timestamp = (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) ? timestamp : 0, + .lifetime = valid_lifetime, + .preferred = preferred_lifetime, + .addr_source = source, + }; + } + + nm_l3_config_data_add_address(l3cd, addr_family, NULL, &a.ax); + } + + while (g_variant_iter_next(route_iter, "a{sv}", &entry_iter)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *entry_iter_free = entry_iter; + const char *dst_addr_str = NULL; + NMIPAddr dst_addr_bin = {}; + uint8_t dst_plen = 0; + const char *router_str = NULL; + NMIPAddr router_bin = {}; + const char *pref_src_str = NULL; + NMIPAddr pref_src_bin = {}; + _nm_unused uint32_t lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + _nm_unused uint32_t priority = 0; + uint8_t preference = 0; + uint32_t mtu = 0; + NMPlatformIPXRoute r; + + while (g_variant_iter_next(entry_iter, "{&sv}", &key, &value)) { + _nm_unused gs_unref_variant GVariant *value_free = value; + + if (nm_streq(key, "Destination")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE("(sy)")) || dst_addr_str) + goto param_error; + + g_variant_get(value, "(&sy)", &dst_addr_str, &dst_plen); + if (inet_pton(addr_family, dst_addr_str, &dst_addr_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "Router")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || router_str) + goto param_error; + + router_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, router_str, &router_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "PreferredSource")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) || pref_src_str) + goto param_error; + + pref_src_str = g_variant_get_string(value, NULL); + if (inet_pton(addr_family, pref_src_str, &pref_src_bin) != 1) + goto param_error; + } + + if (nm_streq(key, "Lifetime")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32) + || lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + goto param_error; + + lifetime = g_variant_get_uint32(value); + } + + if (nm_streq(key, "Priority")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) + goto param_error; + + priority = g_variant_get_uint32(value); + } + + if (nm_streq(key, "Preference")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTE)) + goto param_error; + + preference = g_variant_get_byte(value); + } + + if (nm_streq(key, "MTU")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) + goto param_error; + + mtu = g_variant_get_uint32(value); + } + } + + if (addr_family == AF_INET) { + r.r4 = (NMPlatformIP4Route){ + .network = dst_addr_str ? dst_addr_bin.addr4 : 0, + .plen = dst_addr_str ? dst_plen : 0, + .gateway = router_str ? router_bin.addr4 : 0, + .pref_src = pref_src_str ? pref_src_bin.addr4 : 0, + .scope_inv = + nm_platform_route_scope_inv(router_str ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK), + }; + } else { + r.r6 = (NMPlatformIP6Route){ + .network = dst_addr_str ? dst_addr_bin.addr6 : nm_ip_addr_zero.addr6, + .plen = dst_addr_str ? dst_plen : 0, + .gateway = router_str ? router_bin.addr6 : nm_ip_addr_zero.addr6, + .pref_src = pref_src_str ? pref_src_bin.addr6 : nm_ip_addr_zero.addr6, + .rt_pref = preference, + .r_rtm_flags = RTNH_F_ONLINK, + }; + } + + r.rx.metric_any = TRUE; + r.rx.mtu = mtu; + r.rx.rt_source = source; + r.rx.type_coerced = nm_platform_route_type_coerce(RTN_UNICAST); + r.rx.table_any = TRUE; + + /* TODO: set the lifetime */ + nm_l3_config_data_add_route(l3cd, addr_family, NULL, &r.rx); + } + + if (dns_iter) { + while (g_variant_iter_next(dns_iter, "&s", &str_value)) { + NMIPAddr dns_bin; + + if (inet_pton(addr_family, str_value, &dns_bin) != 1) + goto param_error; + + nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &dns_bin, NULL); + nm_l3_config_data_set_dns_priority(l3cd, addr_family, NM_DNS_PRIORITY_DEFAULT_NORMAL); + } + } + + if (domain_iter) { + while (g_variant_iter_next(domain_iter, "&s", &str_value)) + nm_l3_config_data_add_search(l3cd, addr_family, str_value); + } + + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + nm_l3_config_data_set_mdns(l3cd, mdns); + + return nm_l3_config_data_ref_and_seal(l3cd); + +param_error: + return NULL; +} + +bool +nm_device_iwd_set_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter *config_iter) +{ + NMDevice *device = NM_DEVICE(self); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); + const NML3ConfigData *l3cd; + NMDeviceState state = nm_device_get_state(device); + + if (state < NM_DEVICE_STATE_CONFIG || state > NM_DEVICE_STATE_ACTIVATED) + return FALSE; + + l3cd = nm_device_iwd_parse_netconfig(self, addr_family, config_iter); + if (!l3cd) { + _LOGE(LOGD_WIFI, "Malformed netconfig DBus structure"); + return FALSE; + } + + if (state == NM_DEVICE_STATE_CONFIG) { + nm_l3_config_data_unref(priv->pending_l3cd_x[NM_IS_IPv4(addr_family)]); + priv->pending_l3cd_x[NM_IS_IPv4(addr_family)] = l3cd; + } else { + nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, l3cd); + nm_l3_config_data_unref(l3cd); + } + + return TRUE; +} + static void autoconnect_changed(NMDevice *device, GParamSpec *pspec, NMDeviceIwd *self) { @@ -3411,7 +3825,7 @@ nm_device_iwd_init(NMDeviceIwd *self) g_signal_connect(self, "notify::" NM_DEVICE_AUTOCONNECT, G_CALLBACK(autoconnect_changed), self); /* Make sure the manager is running */ - (void) nm_iwd_manager_get(); + priv->manager = g_object_ref(nm_iwd_manager_get()); } NMDevice * @@ -3443,6 +3857,8 @@ dispose(GObject *object) G_OBJECT_CLASS(nm_device_iwd_parent_class)->dispose(object); nm_assert(c_list_is_empty(&priv->aps_lst_head)); + + g_clear_object(&priv->manager); } static void @@ -3472,12 +3888,14 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) device_class->set_enabled = set_enabled; device_class->get_type_description = get_type_description; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->get_configured_mtu = get_configured_mtu; - device_class->deactivate = deactivate; - device_class->deactivate_async = deactivate_async; - device_class->can_reapply_change = can_reapply_change; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip_config = act_stage3_ip_config; + device_class->ready_for_ip_config = ready_for_ip_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->deactivate_async = deactivate_async; + device_class->can_reapply_change = can_reapply_change; /* Stage 1 needed only for the set_current_ap() call. Stage 2 is * needed if we're assuming a connection still in the "connecting" diff --git a/src/core/devices/wifi/nm-device-iwd.h b/src/core/devices/wifi/nm-device-iwd.h index bb136bf6..8449f7f6 100644 --- a/src/core/devices/wifi/nm-device-iwd.h +++ b/src/core/devices/wifi/nm-device-iwd.h @@ -11,7 +11,7 @@ #include "nm-device-wifi.h" #define NM_TYPE_DEVICE_IWD (nm_device_iwd_get_type()) -#define NM_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) +#define NM_DEVICE_IWD(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) #define NM_DEVICE_IWD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) #define NM_IS_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD)) @@ -46,4 +46,6 @@ void _nm_device_iwd_request_scan(NMDeviceIwd *self, void nm_device_iwd_network_add_remove(NMDeviceIwd *device, GDBusProxy *network, bool add); +bool nm_device_iwd_set_netconfig(NMDeviceIwd *device, int addr_family, GVariantIter *config_iter); + #endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.h b/src/core/devices/wifi/nm-device-olpc-mesh.h index 79b7fd5d..af3abbc0 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.h +++ b/src/core/devices/wifi/nm-device-olpc-mesh.h @@ -15,7 +15,7 @@ #define NM_TYPE_DEVICE_OLPC_MESH (nm_device_olpc_mesh_get_type()) #define NM_DEVICE_OLPC_MESH(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) #define NM_DEVICE_OLPC_MESH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) #define NM_IS_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OLPC_MESH)) diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index 4576af95..6c0a4d5e 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -22,7 +22,6 @@ #include "nm-act-request.h" #include "nm-l3-config-data.h" #include "nm-manager.h" -#include "nm-manager.h" #include "nm-setting-wifi-p2p.h" #include "nm-utils.h" #include "nm-wifi-p2p-peer.h" diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.h b/src/core/devices/wifi/nm-device-wifi-p2p.h index d1aadd8e..08780464 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.h +++ b/src/core/devices/wifi/nm-device-wifi-p2p.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_WIFI_P2P (nm_device_wifi_p2p_get_type()) #define NM_DEVICE_WIFI_P2P(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) #define NM_DEVICE_WIFI_P2P_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) #define NM_IS_DEVICE_WIFI_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI_P2P)) diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 8af974d0..171743d0 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -99,13 +99,13 @@ typedef struct { NMSupplMgrCreateIfaceHandle *sup_create_handle; NMSupplicantInterface *sup_iface; + GSource *scan_kickoff_timeout_source; + gint64 scan_last_complete_msec; gint64 scan_periodic_next_msec; gint64 scan_last_request_started_at_msec; - guint scan_kickoff_timeout_id; - guint ap_dump_id; guint periodic_update_id; @@ -508,7 +508,10 @@ _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff) /* something prohibits scanning. */ } else if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP)) { /* Don't scan when a an AP or Ad-Hoc connection is active as it will - * disrupt connected clients or peers. */ + * disrupt connected clients or peers. + * + * Explicit scans are allowed however. */ + explicit_allowed = TRUE; } else if (NM_IN_SET(state, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_FAILED)) { /* Can always scan when disconnected */ explicit_allowed = TRUE; @@ -659,7 +662,7 @@ supplicant_interface_release(NMDeviceWifi *self) NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - nm_clear_g_source(&priv->scan_kickoff_timeout_id); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); nm_clear_g_source_inst(&priv->scan_request_delay_source); nm_clear_g_cancellable(&priv->scan_request_cancellable); @@ -1718,9 +1721,9 @@ _scan_kickoff_timeout_cb(gpointer user_data) NMDeviceWifi *self = user_data; NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - priv->scan_kickoff_timeout_id = 0; + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); _scan_kickoff(self); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } static void @@ -1763,13 +1766,13 @@ _scan_kickoff(NMDeviceWifi *self) / 1000), (int) ((priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec) % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id + !priv->scan_kickoff_timeout_source ? ", schedule timeout" : ""); + if (!priv->scan_kickoff_timeout_source && (priv->scan_explicit_allowed || priv->scan_periodic_allowed)) { - priv->scan_kickoff_timeout_id = g_timeout_add(priv->scan_last_request_started_at_msec - + ratelimit_duration_msec - now_msec, - _scan_kickoff_timeout_cb, - self); + priv->scan_kickoff_timeout_source = nm_g_timeout_add_source( + priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec, + _scan_kickoff_timeout_cb, + self); } return; } @@ -1786,14 +1789,16 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (rate limited for another %d.%03d sec after previous scan)", timeout_msec / 1000, timeout_msec % 1000); - nm_clear_g_source(&priv->scan_kickoff_timeout_id); - priv->scan_kickoff_timeout_id = g_timeout_add(timeout_msec, _scan_kickoff_timeout_cb, self); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); + priv->scan_kickoff_timeout_source = + nm_g_timeout_add_source(timeout_msec, _scan_kickoff_timeout_cb, self); return; } if (priv->scan_explicit_requested) { if (!priv->scan_explicit_allowed) { - _LOGT_scan("kickoff: don't scan (explicit scan requested but not allowed)"); + _LOGT_scan( + "kickoff: don't scan (explicit scan requested but not allowed at the moment)"); return; } priv->scan_explicit_requested = FALSE; @@ -1803,7 +1808,7 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (periodic scan currently not allowed)"); priv->scan_periodic_next_msec = 0; priv->scan_periodic_interval_sec = 0; - nm_clear_g_source(&priv->scan_kickoff_timeout_id); + nm_clear_g_source_inst(&priv->scan_kickoff_timeout_source); return; } @@ -1813,12 +1818,12 @@ _scan_kickoff(NMDeviceWifi *self) _LOGT_scan("kickoff: don't scan (periodic scan waiting for another %d.%03d sec%s)", (int) ((priv->scan_periodic_next_msec - now_msec) / 1000), (int) ((priv->scan_periodic_next_msec - now_msec) % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id) { - priv->scan_kickoff_timeout_id = - g_timeout_add_seconds((priv->scan_periodic_next_msec - now_msec + 999) / 1000, - _scan_kickoff_timeout_cb, - self); + !priv->scan_kickoff_timeout_source ? ", schedule timeout" : ""); + if (!priv->scan_kickoff_timeout_source) { + priv->scan_kickoff_timeout_source = nm_g_timeout_add_seconds_source( + (priv->scan_periodic_next_msec - now_msec + 999) / 1000, + _scan_kickoff_timeout_cb, + self); } return; } diff --git a/src/core/devices/wifi/nm-device-wifi.h b/src/core/devices/wifi/nm-device-wifi.h index 3a85192e..17893a1b 100644 --- a/src/core/devices/wifi/nm-device-wifi.h +++ b/src/core/devices/wifi/nm-device-wifi.h @@ -10,7 +10,8 @@ #include "devices/nm-device.h" #define NM_TYPE_DEVICE_WIFI (nm_device_wifi_get_type()) -#define NM_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) +#define NM_DEVICE_WIFI(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) #define NM_DEVICE_WIFI_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) #define NM_IS_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI)) diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index 2e0d51e5..0d4daf21 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -47,13 +47,18 @@ typedef struct { } KnownNetworkData; typedef struct { + GBytes *ssid; + gint64 timestamp; +} RecentlyMirroredData; + +typedef struct { NMManager *manager; NMSettings *settings; GCancellable *cancellable; gboolean running; GDBusObjectManager *object_manager; guint agent_id; - char *agent_path; + guint netconfig_agent_id; GHashTable *known_networks; NMDeviceIwd *last_agent_call_device; char *last_state_dir; @@ -62,6 +67,7 @@ typedef struct { GHashTable *p2p_devices; NMIwdWfdInfo wfd_info; guint wfd_use_count; + GSList *recently_mirrored; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -271,6 +277,77 @@ return_error: "Secrets not available for this connection"); } +static void +netconfig_agent_dbus_method_cb(GDBusConnection *connection, + const char *sender, + const char *object_path, + const char *interface_name, + const char *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + gs_free char *name_owner = NULL; + const char *device_path; + gs_unref_object GDBusInterface *device_obj = NULL; + NMDevice *device; + nm_auto_free_variant_iter GVariantIter *config_iter = NULL; + const char *ifname; + int addr_family; + + /* Be paranoid and check the sender address */ + name_owner = g_dbus_object_manager_client_get_name_owner( + G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager)); + if (!nm_streq0(name_owner, sender)) + goto return_error; + + if (nm_streq(method_name, "ConfigureIPv4")) + addr_family = AF_INET; + else if (nm_streq(method_name, "ConfigureIPv6")) + addr_family = AF_INET6; + else + goto return_error; + + g_variant_get(parameters, "(&oa{sv})", &device_path, &config_iter); + + device_obj = g_dbus_object_manager_get_interface(priv->object_manager, + device_path, + NM_IWD_DEVICE_INTERFACE); + if (!device_obj) { + _LOGE("netconfig-agent-request: unable to find the device object"); + goto return_error; + } + + ifname = get_property_string_or_null(G_DBUS_PROXY(device_obj), "Name"); + if (!ifname) { + _LOGD("Name not cached for device at %s", device_path); + goto return_error; + } + + device = nm_manager_get_device(priv->manager, ifname, NM_DEVICE_TYPE_WIFI); + if (!device || !NM_IS_DEVICE_IWD(device)) { + _LOGD("NM device %s is not an IWD-managed device", ifname); + goto return_error; + } + + if (nm_device_iwd_set_netconfig(NM_DEVICE_IWD(device), addr_family, config_iter)) { + g_dbus_method_invocation_return_value(invocation, g_variant_new("()")); + return; + } + + _LOGD("netconfig-agent-request: device %s did not handle the IWD Netconfig Agent request", + ifname); + +return_error: + /* IWD doesn't look at the specific error */ + g_dbus_method_invocation_return_error_literal(invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "Couldn't set netconfig data"); +} + static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( "net.connman.iwd.Agent", .methods = NM_DEFINE_GDBUS_METHOD_INFOS( @@ -296,36 +373,55 @@ static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE .in_args = NM_DEFINE_GDBUS_ARG_INFOS( NM_DEFINE_GDBUS_ARG_INFO("reason", "s"), ), ), ), ); +static const GDBusInterfaceInfo iwd_netconfig_agent_iface_info = + NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + "net.connman.iwd.NetworkConfigurationAgent", + .methods = NM_DEFINE_GDBUS_METHOD_INFOS( + NM_DEFINE_GDBUS_METHOD_INFO("ConfigureIPv4", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("device", "o"), + NM_DEFINE_GDBUS_ARG_INFO("config", "a{sv}"), ), ), + NM_DEFINE_GDBUS_METHOD_INFO("ConfigureIPv6", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("device", "o"), + NM_DEFINE_GDBUS_ARG_INFO("config", "a{sv}"), ), ), ), ); + static guint -iwd_agent_export(GDBusConnection *connection, gpointer user_data, char **agent_path, GError **error) +iwd_agent_export(GDBusConnection *connection, gpointer user_data, GError **error) { static const GDBusInterfaceVTable vtable = { .method_call = agent_dbus_method_cb, }; - char path[50]; - unsigned int rnd; - guint id; - nm_random_get_bytes(&rnd, sizeof(rnd)); - - nm_sprintf_buf(path, "/agent/%u", rnd); + return g_dbus_connection_register_object( + connection, + NM_IWD_AGENT_PATH, + NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info), + &vtable, + user_data, + NULL, + error); +} - id = - g_dbus_connection_register_object(connection, - path, - NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info), - &vtable, - user_data, - NULL, - error); +static guint +iwd_netconfig_agent_export(GDBusConnection *connection, gpointer user_data, GError **error) +{ + static const GDBusInterfaceVTable vtable = { + .method_call = netconfig_agent_dbus_method_cb, + }; - if (id) - *agent_path = g_strdup(path); - return id; + return g_dbus_connection_register_object( + connection, + NM_IWD_AGENT_PATH, + NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_netconfig_agent_iface_info), + &vtable, + user_data, + NULL, + error); } static void -register_agent(NMIwdManager *self) +register_agent(NMIwdManager *self, const char *method) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); GDBusInterface *agent_manager; @@ -334,14 +430,14 @@ register_agent(NMIwdManager *self) "/net/connman/iwd", /* IWD 1.0+ */ NM_IWD_AGENT_MANAGER_INTERFACE); if (!agent_manager) { - _LOGE("unable to register the IWD Agent: PSK/8021x Wi-Fi networks may not work"); + _LOGE("unable to register the IWD Agent"); return; } /* Register our agent */ g_dbus_proxy_call(G_DBUS_PROXY(agent_manager), - "RegisterAgent", - g_variant_new("(o)", priv->agent_path), + method, + g_variant_new("(o)", NM_IWD_AGENT_PATH), G_DBUS_CALL_FLAGS_NONE, -1, NULL, @@ -353,6 +449,70 @@ register_agent(NMIwdManager *self) /*****************************************************************************/ +static void +recently_mirrored_data_free(void *data) +{ + RecentlyMirroredData *rmd = data; + + g_bytes_unref(rmd->ssid); + g_free(rmd); +} + +/* When we mirror an 802.1x connection to an IWD config file, and there's an + * AP in range with matching SSID, that connection should become available + * for activation. In IWD terms when an 802.1x network becomes a Known + * Network, it can be connected to using the .Connect D-Bus method. + * + * However there's a delay between writing the IWD config file and receiving + * the InterfaceAdded event for the Known Network so we don't immediately + * find out that the network can now be used. If an NM client creates a + * new connection for an 802.1x AP and tries to activate it immediately, + * NMDeviceIWD will not allow it to because it doesn't know the network is + * known yet. To work around this, we save the SSIDs of 802.1x connections + * we recently mirrored to IWD config files, for 2 seconds, and we treat + * them as Known Networks in that period since in theory activations should + * succeed. + */ +bool +nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + gint64 now = nm_utils_get_monotonic_timestamp_nsec(); + GSList *iter; + RecentlyMirroredData *rmd; + + /* Drop entries older than 2 seconds */ + while (priv->recently_mirrored) { + rmd = priv->recently_mirrored->data; + if (now < rmd->timestamp + 2000000000) + break; + + priv->recently_mirrored = g_slist_remove(priv->recently_mirrored, rmd); + recently_mirrored_data_free(rmd); + } + + for (iter = priv->recently_mirrored; iter; iter = iter->next) { + rmd = iter->data; + if (g_bytes_equal(ssid, rmd->ssid)) + return TRUE; + } + + return FALSE; +} + +static void +save_mirrored(NMIwdManager *self, GBytes *ssid) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + RecentlyMirroredData *rmd = g_malloc(sizeof(RecentlyMirroredData)); + + rmd->ssid = g_bytes_ref(ssid); + rmd->timestamp = nm_utils_get_monotonic_timestamp_nsec(); + priv->recently_mirrored = g_slist_append(priv->recently_mirrored, rmd); +} + +/*****************************************************************************/ + static KnownNetworkId * known_network_id_new(const char *name, NMIwdNetworkSecurity security) { @@ -721,6 +881,9 @@ sett_conn_changed(NMSettingsConnection *sett_conn, "iwd: changed Wi-Fi connection %s mirrored as IWD profile %s", nm_settings_connection_get_id(sett_conn), full_path); + + if (security == NM_IWD_NETWORK_SECURITY_8021X) + save_mirrored(nm_iwd_manager_get(), ssid); } /* Look up an existing NMSettingsConnection for a network that has been @@ -1283,6 +1446,7 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer gs_free_error GError *error = NULL; nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; NMSettingsConnectionIntFlags flags; + NMIwdNetworkSecurity security; if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless")) return; @@ -1338,6 +1502,12 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer _LOGD("New Wi-Fi connection %s mirrored as IWD profile %s", nm_settings_connection_get_id(sett_conn), full_path); + + if (nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_8021X) { + NMSettingWireless *s_wifi = nm_connection_get_setting_wireless(conn); + save_mirrored(nm_iwd_manager_get(), nm_setting_wireless_get_ssid(s_wifi)); + } } static gboolean @@ -1355,26 +1525,33 @@ _om_has_name_owner(GDBusObjectManager *object_manager) static void release_object_manager(NMIwdManager *self) { - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + GDBusConnection *agent_connection; + GDBusObjectManagerClient *omc; if (!priv->object_manager) return; g_signal_handlers_disconnect_by_data(priv->object_manager, self); - if (priv->agent_id) { - GDBusConnection *agent_connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager); - - agent_connection = g_dbus_object_manager_client_get_connection(omc); + omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager); + agent_connection = g_dbus_object_manager_client_get_connection(omc); - /* We're is called when we're shutting down (i.e. our DBus connection - * is being closed, and IWD will detect this) or IWD was stopped so - * in either case calling UnregisterAgent will not do anything. - */ + /* We're called when we're shutting down (i.e. our DBus connection + * is being closed, and IWD will detect this) or IWD was stopped so + * in either case calling UnregisterAgent will not do anything. + * Just unregister the agent interfaces. The agents are on the same + * object (same path) but it seems g_dbus_connection_unregister_object() + * should be called for each interface on the object separately. + */ + if (priv->agent_id) { g_dbus_connection_unregister_object(agent_connection, priv->agent_id); priv->agent_id = 0; - nm_clear_g_free(&priv->agent_path); + } + + if (priv->netconfig_agent_id) { + g_dbus_connection_unregister_object(agent_connection, priv->netconfig_agent_id); + priv->netconfig_agent_id = 0; } g_clear_object(&priv->object_manager); @@ -1589,6 +1766,10 @@ next: } g_variant_iter_free(properties_iter); + + /* Register the netconfig agent only once we know netconfig is enabled */ + if (nm_iwd_manager_get_netconfig_enabled(self) && priv->netconfig_agent_id) + register_agent(self, "RegisterNetworkConfigurationAgent"); } static void @@ -1620,13 +1801,19 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) connection = g_dbus_object_manager_client_get_connection(G_DBUS_OBJECT_MANAGER_CLIENT(object_manager)); - priv->agent_id = iwd_agent_export(connection, self, &priv->agent_path, &error); + priv->agent_id = iwd_agent_export(connection, self, &error); if (!priv->agent_id) { _LOGE("failed to export the IWD Agent: PSK/8021x Wi-Fi networks may not work: %s", error->message); g_clear_error(&error); } + priv->netconfig_agent_id = iwd_netconfig_agent_export(connection, self, &error); + if (!priv->netconfig_agent_id) { + _LOGE("failed to export the IWD Netconfig Agent: %s", error->message); + g_clear_error(&error); + } + if (_om_has_name_owner(object_manager)) { GList *objects, *iter; gs_unref_object GDBusInterface *daemon = NULL; @@ -1654,7 +1841,7 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) g_list_free_full(objects, g_object_unref); if (priv->agent_id) - register_agent(self); + register_agent(self, "RegisterAgent"); priv->netconfig_enabled = false; /* Assume false until GetInfo() results come in */ @@ -1952,6 +2139,8 @@ dispose(GObject *object) g_hash_table_unref(nm_steal_pointer(&priv->p2p_devices)); + g_slist_free_full(nm_steal_pointer(&priv->recently_mirrored), recently_mirrored_data_free); + G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); } diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h index 02cd6bba..80123c9a 100644 --- a/src/core/devices/wifi/nm-iwd-manager.h +++ b/src/core/devices/wifi/nm-iwd-manager.h @@ -30,8 +30,11 @@ #define NM_IWD_P2P_SERVICE_MANAGER_INTERFACE "net.connman.iwd.p2p.ServiceManager" #define NM_IWD_P2P_WFD_INTERFACE "net.connman.iwd.p2p.Display" +#define NM_IWD_AGENT_PATH NM_DBUS_PATH "/iwd/agent" + #define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type()) -#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) +#define NM_IWD_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) #define NM_IWD_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IWD_MANAGER, NMIwdManagerClass)) #define NM_IS_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IWD_MANAGER)) @@ -63,4 +66,6 @@ gboolean nm_iwd_manager_check_wfd_info_compatible(NMIwdManager *self, const NMIw gboolean nm_iwd_manager_register_wfd(NMIwdManager *self, const NMIwdWfdInfo *wfd_info); void nm_iwd_manager_unregister_wfd(NMIwdManager *self); +bool nm_iwd_manager_is_recently_mirrored(NMIwdManager *self, const GBytes *ssid); + #endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h index c0422900..93dc8edf 100644 --- a/src/core/devices/wifi/nm-wifi-ap.h +++ b/src/core/devices/wifi/nm-wifi-ap.h @@ -13,7 +13,7 @@ #include "libnm-base/nm-base.h" #define NM_TYPE_WIFI_AP (nm_wifi_ap_get_type()) -#define NM_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) +#define NM_WIFI_AP(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) #define NM_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_AP, NMWifiAPClass)) #define NM_IS_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_AP)) #define NM_IS_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_AP)) diff --git a/src/core/devices/wifi/nm-wifi-factory.c b/src/core/devices/wifi/nm-wifi-factory.c index 5e354c6b..19880a90 100644 --- a/src/core/devices/wifi/nm-wifi-factory.c +++ b/src/core/devices/wifi/nm-wifi-factory.c @@ -24,7 +24,7 @@ #define NM_TYPE_WIFI_FACTORY (nm_wifi_factory_get_type()) #define NM_WIFI_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactory)) #define NM_WIFI_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_FACTORY, NMWifiFactoryClass)) #define NM_IS_WIFI_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_FACTORY)) diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.h b/src/core/devices/wifi/nm-wifi-p2p-peer.h index 5124d1de..b0abeb37 100644 --- a/src/core/devices/wifi/nm-wifi-p2p-peer.h +++ b/src/core/devices/wifi/nm-wifi-p2p-peer.h @@ -12,7 +12,7 @@ #define NM_TYPE_WIFI_P2P_PEER (nm_wifi_p2p_peer_get_type()) #define NM_WIFI_P2P_PEER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) #define NM_WIFI_P2P_PEER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) #define NM_IS_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_P2P_PEER)) diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index 1a8204b0..8a8d062f 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -11,6 +11,7 @@ #include <netinet/if_ether.h> #include <stdlib.h> +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" @@ -812,13 +813,12 @@ nm_wifi_utils_complete_connection(GBytes *ap_ssid, * setting. Since there's so much configuration required for it, there's * no way it can be automatically completed. */ - } else if (nm_streq0(key_mgmt, "wpa-psk") - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE - && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK - || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK))) { + } else if (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE + && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-psk", + nm_streq0(key_mgmt, "sae") ? "sae" : "wpa-psk", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); @@ -828,7 +828,7 @@ nm_wifi_utils_complete_connection(GBytes *ap_ssid, || NM_FLAGS_ANY(ap_rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "owe", NULL); - } else if (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + } else if (nm_streq0(key_mgmt, "wpa-psk") || ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, @@ -1004,7 +1004,7 @@ psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GEr if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { nm_log_info( LOGD_WIFI, - "IWD network config is being created wihout the PSK but IWD will save the PSK on " + "IWD network config is being created without the PSK but IWD will save the PSK on " "successful activation not honoring the psk-flags property"); } return TRUE; @@ -1549,10 +1549,16 @@ eap_setting_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, GError **erro } static gboolean -ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +ip_config_to_iwd_config(int addr_family, GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) { - guint num; - struct in_addr ip; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_488, FALSE); + NMIPAddress *addr; + guint num; + guint i; + char buf[NM_INET_ADDRSTRLEN + 10]; + const char *kf_group = IS_IPv4 ? "IPv4" : "IPv6"; + const char *gw; /* These settings are not acutally used unless global * [General].EnableNetworkConfiguration is true, which we don't support. @@ -1564,15 +1570,26 @@ ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error if (!s_ip) return TRUE; + nm_assert(NM_IS_IPv4(addr_family) ? NM_IS_SETTING_IP4_CONFIG(s_ip) + : NM_IS_SETTING_IP6_CONFIG(s_ip)); + num = nm_setting_ip_config_get_num_dns(s_ip); if (num) { - nm_auto_free_gstring GString *s = g_string_sized_new(128); - guint i; - + nm_str_buf_reset(&strbuf); for (i = 0; i < num; i++) { - if (s->len) - g_string_append_c(s, ' '); - g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + char sbuf[NM_INET_ADDRSTRLEN]; + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(addr_family, + nm_setting_ip_config_get_dns(s_ip, i), + NULL, + &a, + NULL)) + continue; + + if (strbuf.len > 0) + nm_str_buf_append_c(&strbuf, ' '); + nm_str_buf_append(&strbuf, nm_inet_ntop(addr_family, &a, sbuf)); } /* It doesn't matter whether we add the DNS under [IPv4] or [IPv6] * except that with method=auto the list will override the @@ -1581,97 +1598,61 @@ ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error * Note ignore-auto-dns=false isn't supported, this list always * overrides the DHCP DNSes. */ - g_key_file_set_string(file, "IPv4", "DNS", s->str); + g_key_file_set_string(file, kf_group, "DNS", nm_str_buf_get_str(&strbuf)); } - if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - return TRUE; - - num = nm_setting_ip_config_get_num_addresses(s_ip); - if (num) { - NMIPAddress *addr = nm_setting_ip_config_get_address(s_ip, 0); - guint prefix = nm_ip_address_get_prefix(addr); - in_addr_t netmask = _nm_utils_ip4_prefix_to_netmask(prefix); - char buf[INET_ADDRSTRLEN]; - - nm_ip_address_get_address_binary(addr, &ip); - g_key_file_set_string(file, "IPv4", "Address", nm_ip_address_get_address(addr)); - g_key_file_set_string(file, "IPv4", "Netmask", _nm_utils_inet4_ntop(netmask, buf)); - } else { - inet_pton(AF_INET, "10.42.0.100", &ip); - g_key_file_set_string(file, "IPv4", "Address", "10.42.0.100"); + if (!IS_IPv4) { + if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + g_key_file_set_boolean(file, kf_group, "Enabled", TRUE); } - if (nm_setting_ip_config_get_gateway(s_ip)) { - g_key_file_set_string(file, "IPv4", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); - } else { - uint32_t val; - char buf[INET_ADDRSTRLEN]; - - /* IWD won't enable static IP unless both Address and Gateway are - * set so generate a gateway address if not known. - */ - val = (ntohl(ip.s_addr) & 0xfffffff0) + 1; - if (val == ntohl(ip.s_addr)) - val += 1; - g_key_file_set_string(file, "IPv4", "Gateway", _nm_utils_inet4_ntop(htonl(val), buf)); - } - - return TRUE; -} - -static gboolean -ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) -{ - guint num; - NMIPAddress *addr; - char buf[INET6_ADDRSTRLEN + 10]; - - if (!s_ip) + num = nm_setting_ip_config_get_num_addresses(s_ip); + if (num == 0) return TRUE; - num = nm_setting_ip_config_get_num_dns(s_ip); - if (num) { - nm_auto_free_gstring GString *s = g_string_sized_new(128); - guint i; + addr = nm_setting_ip_config_get_address(s_ip, 0); + gw = nm_setting_ip_config_get_gateway(s_ip); - for (i = 0; i < num; i++) { - if (s->len) - g_string_append_c(s, ' '); - g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); - } - g_key_file_set_string(file, "IPv6", "DNS", s->str); - } + if (IS_IPv4) { + in_addr_t ip; - if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - return TRUE; + nm_ip_address_get_address_binary(addr, &ip); - g_key_file_set_boolean(file, "IPv6", "Enabled", TRUE); + g_key_file_set_string(file, kf_group, "Address", nm_ip_address_get_address(addr)); + g_key_file_set_string( + file, + kf_group, + "Netmask", + nm_inet4_ntop(nm_ip4_addr_netmask_from_prefix(nm_ip_address_get_prefix(addr)), buf)); - if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - return TRUE; + if (!gw) { + guint32 val; - if (!nm_setting_ip_config_get_num_addresses(s_ip)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - "IP address required for IPv6 manual config"); - return FALSE; + /* IWD won't enable static IP unless both Address and Gateway are + * set so generate a gateway address if not known. + */ + val = (ntohl(ip) & 0xfffffff0) + 1; + if (val == ntohl(ip)) + val += 1; + gw = nm_inet4_ntop(htonl(val), buf); + } + g_key_file_set_string(file, kf_group, "Gateway", gw); + } else { + g_key_file_set_string(file, + kf_group, + "Address", + nm_sprintf_buf(buf, + "%s/%u", + nm_ip_address_get_address(addr), + nm_ip_address_get_prefix(addr))); + if (gw) + g_key_file_set_string(file, kf_group, "Gateway", gw); } - addr = nm_setting_ip_config_get_address(s_ip, 0); - g_key_file_set_string(file, - "IPv6", - "Address", - nm_sprintf_buf(buf, - "%s/%u", - nm_ip_address_get_address(addr), - nm_ip_address_get_prefix(addr))); - if (nm_setting_ip_config_get_gateway(s_ip)) - g_key_file_set_string(file, "IPv6", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); return TRUE; } @@ -1759,13 +1740,15 @@ nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, else if (cloned_mac_addr && nm_utils_hwaddr_valid(cloned_mac_addr, ETH_ALEN)) g_key_file_set_string(file, "Settings", "AddressOverride", cloned_mac_addr); - if (!ip4_config_to_iwd_config( + if (!ip_config_to_iwd_config( + AF_INET, file, NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip4_config(connection)), error)) return NULL; - if (!ip6_config_to_iwd_config( + if (!ip_config_to_iwd_config( + AF_INET6, file, NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip6_config(connection)), error)) diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index e0209aff..b83120f9 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -273,6 +273,15 @@ modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_d /* Called when the ModemManager modem enabled state is changed externally * to NetworkManager (eg something using MM's D-Bus API directly). */ + + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled) { + /* We cannot re-enable this modem, thus device becomes unavailable. */ + nm_device_state_changed(device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + return; + } + if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { /* user-initiated action, hence DISCONNECTED not FAILED */ nm_device_state_changed(device, @@ -435,6 +444,13 @@ check_connection_available(NMDevice *device, return FALSE; } + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && state <= NM_MODEM_STATE_DISABLING) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem is disabled and NM cannot enable it"); + return FALSE; + } + if (state == NM_MODEM_STATE_LOCKED) { if (!nm_connection_get_setting_gsm(connection)) { nm_utils_error_set_literal(error, @@ -599,6 +615,11 @@ set_enabled(NMDevice *device, gboolean enabled) if (enabled == FALSE) { nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); + } else { + /* It's possible that the modem is enabled outside of NM. Need to recheck. */ + nm_device_queue_recheck_available(device, + NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, + NM_DEVICE_STATE_REASON_MODEM_FAILED); } } @@ -617,6 +638,9 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) if (modem_state <= NM_MODEM_STATE_INITIALIZING) return FALSE; + if (!NM_MODEM_GET_CLASS(priv->modem)->set_mm_enabled && modem_state <= NM_MODEM_STATE_DISABLING) + return FALSE; + return TRUE; } diff --git a/src/core/devices/wwan/nm-device-modem.h b/src/core/devices/wwan/nm-device-modem.h index f171d76f..317a5bde 100644 --- a/src/core/devices/wwan/nm-device-modem.h +++ b/src/core/devices/wwan/nm-device-modem.h @@ -11,7 +11,7 @@ #define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type()) #define NM_DEVICE_MODEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) #define NM_DEVICE_MODEM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) #define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MODEM)) diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index db4fb29f..f0907c46 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -636,7 +636,7 @@ connect_context_step(NMModemBroadband *self) if (ctx->ip_types_i < ctx->ip_types->len) { NMModemIPType current; - current = g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); + current = nm_g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); if (current == NM_MODEM_IP_TYPE_IPV4) mm_simple_connect_properties_set_ip_type(ctx->connect_properties, @@ -993,7 +993,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Fully fail if invalid IP address retrieved */ address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); if (!address_string - || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { + || !nm_inet_parse_bin(AF_INET, address_string, NULL, &address_network)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1005,7 +1005,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho /* Missing gateway not a hard failure */ gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); - if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { + if (gw_string && !nm_inet_parse_bin(AF_INET, gw_string, NULL, &gw)) { g_set_error(&error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -1057,9 +1057,8 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) - && address_network > 0) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &address_network); + if (nm_inet_parse_bin(AF_INET, dns[i], NULL, &address_network) && address_network > 0) { + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &address_network, NULL); _LOGI(" DNS %s", dns[i]); } } @@ -1174,7 +1173,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho struct in6_addr addr; if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &addr, NULL); _LOGI(" DNS %s", dns[i]); } } diff --git a/src/core/devices/wwan/nm-modem-broadband.h b/src/core/devices/wwan/nm-modem-broadband.h index 627fe25a..e4467310 100644 --- a/src/core/devices/wwan/nm-modem-broadband.h +++ b/src/core/devices/wwan/nm-modem-broadband.h @@ -10,7 +10,7 @@ #define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type()) #define NM_MODEM_BROADBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) #define NM_MODEM_BROADBAND_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) #define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_BROADBAND)) diff --git a/src/core/devices/wwan/nm-modem-manager.h b/src/core/devices/wwan/nm-modem-manager.h index e89a032b..a9339ffc 100644 --- a/src/core/devices/wwan/nm-modem-manager.h +++ b/src/core/devices/wwan/nm-modem-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type()) #define NM_MODEM_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) #define NM_MODEM_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) #define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_MANAGER)) diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index fc27c3fd..33a19e93 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -7,8 +7,12 @@ #include "nm-modem-ofono.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-uuid.h" #include "devices/nm-device-private.h" +#include "nm-setting-gsm.h" +#include "settings/nm-settings.h" #include "nm-modem.h" #include "libnm-platform/nm-platform.h" #include "nm-l3-config-data.h" @@ -27,27 +31,44 @@ /*****************************************************************************/ typedef struct { + NMModemOfono *self; + char *name; + char *type; + gboolean preferred; + GDBusProxy *proxy; +} OfonoContextData; + +typedef struct { GHashTable *connect_properties; + GHashTable *connections; + GHashTable *contexts; GDBusProxy *modem_proxy; GDBusProxy *connman_proxy; - GDBusProxy *context_proxy; GDBusProxy *sim_proxy; GCancellable *modem_proxy_cancellable; GCancellable *connman_proxy_cancellable; - GCancellable *context_proxy_cancellable; + GCancellable *connect_cancellable; GCancellable *sim_proxy_cancellable; GError *property_error; - char *context_path; char *imsi; gboolean modem_online; + gboolean connman_powered; gboolean gprs_attached; NML3ConfigData *l3cd_4; + NMSettings *settings; + + guint n_context_proxy_pending; + + /* unowned; reference held by 'contexts' above. */ + OfonoContextData *current_octx; + + GSource *deferred_connection_timeout_source; } NMModemOfonoPrivate; struct _NMModemOfono { @@ -96,6 +117,21 @@ G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) /*****************************************************************************/ +/* + * Deterministic UUID is used to pair imsi+context with exported connection + * (via a pair of hash tables). + */ + +static char * +_generate_uuid(const char *imsi, const char *object_path) +{ + return nm_uuid_generate_from_strings( + NM_UUID_TYPE_VERSION5, + &NM_UUID_INIT(b5, 6b, ad, f5, ef, 9d, 4a, 21, a8, e7, 7d, db, 69, bb, 6b, ee), + imsi, + object_path); +} + static void get_capabilities(NMModem *_self, NMDeviceModemCapabilities *modem_caps, @@ -106,6 +142,8 @@ get_capabilities(NMModem *_self, *current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; } +static void do_context_activate(NMModemOfono *self); + static void update_modem_state(NMModemOfono *self) { @@ -114,13 +152,16 @@ update_modem_state(NMModemOfono *self) NMModemState new_state = NM_MODEM_STATE_DISABLED; const char *reason = NULL; - _LOGI("'Attached': %s 'Online': %s 'IMSI': %s", + _LOGI("'Attached': %s 'Online': %s 'Powered': %s 'IMSI': %s", priv->gprs_attached ? "true" : "false", priv->modem_online ? "true" : "false", + priv->connman_powered ? "true" : "false", priv->imsi); if (priv->modem_online == FALSE) { reason = "modem 'Online=false'"; + } else if (priv->connman_powered == FALSE) { + reason = "ConnectionManager 'Powered=false'"; } else if (priv->imsi == NULL && state != NM_MODEM_STATE_ENABLING) { reason = "modem not ready"; } else if (priv->gprs_attached == FALSE) { @@ -131,8 +172,27 @@ update_modem_state(NMModemOfono *self) reason = "modem ready"; } - if (state != new_state) + if (state != new_state) { + if (new_state == NM_MODEM_STATE_DISABLED && priv->deferred_connection_timeout_source) { + /* + * Do this before set_state(), because we want the final device state + * to be "unavailable", not "failed" or "disconnected". + */ + _LOGI("canceling deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); + } + nm_modem_set_state(NM_MODEM(self), new_state, reason); + + if (new_state == NM_MODEM_STATE_REGISTERED && priv->deferred_connection_timeout_source) { + _LOGI("resuming deferred context activation"); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + do_context_activate(self); + } + } } /* Disconnect */ @@ -213,7 +273,8 @@ disconnect(NMModem *modem, ctx->callback = callback; ctx->callback_user_data = user_data; - if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) { + if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable) + || priv->current_octx == NULL) { nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); return; } @@ -222,7 +283,7 @@ disconnect(NMModem *modem, NM_MODEM_STATE_DISCONNECTING, nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING)); - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", warn)), G_DBUS_CALL_FLAGS_NONE, @@ -230,6 +291,8 @@ disconnect(NMModem *modem, ctx->cancellable, disconnect_done, ctx); + + priv->current_octx = NULL; } static void @@ -251,7 +314,7 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *id; + const char *uuid; if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { nm_utils_error_set(error, @@ -268,19 +331,12 @@ check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, return FALSE; } - id = nm_connection_get_id(connection); - - if (!strstr(id, "/context")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID has no context"); - return FALSE; - } + uuid = nm_connection_get_uuid(connection); - if (!strstr(id, priv->imsi)) { + if (!g_hash_table_contains(priv->contexts, uuid)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID does not contain the IMSI"); + "connection ID does not match known contexts"); return FALSE; } @@ -398,11 +454,11 @@ _sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->sim_proxy = proxy; /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(sim_property_changed), + self); g_dbus_proxy_call(priv->sim_proxy, "GetProperties", @@ -469,6 +525,19 @@ handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gp update_modem_state(self); } + } else if (nm_streq(property, "Powered") && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { + gboolean powered = g_variant_get_boolean(v); + gboolean old_powered = priv->connman_powered; + + _LOGD("Powered: %s", powered ? "True" : "False"); + + if (old_powered != powered) { + priv->connman_powered = powered; + + _LOGI("Powered %s -> %s", old_powered ? "true" : "false", powered ? "true" : "false"); + + update_modem_state(self); + } } } @@ -484,7 +553,6 @@ static void connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; - NMModemOfonoPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *v_properties = NULL; gs_unref_variant GVariant *v_dict = NULL; @@ -498,9 +566,6 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user return; self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->connman_proxy_cancellable); if (!v_properties) { g_dbus_error_strip_remote_error(error); @@ -526,6 +591,365 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user } static void +ofono_context_data_free(OfonoContextData *octx) +{ + g_free(octx->name); + g_free(octx->type); + + if (octx->proxy) { + g_signal_handlers_disconnect_by_data(octx->proxy, octx); + g_object_unref(octx->proxy); + } + + g_slice_free(OfonoContextData, octx); +} + +static void +add_or_update_connection(NMModemOfono *self, const char *context_name, const char *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_object NMConnection *connection = NULL; + NMSetting *setting; + NMSettingsConnection *sett_conn; + gs_free_error GError *error = NULL; + + /* + * See first if we have an existing connection (from previous or current + * run of NM) that we can update in-place. + */ + + sett_conn = nm_settings_get_connection_by_uuid(priv->settings, uuid); + if (sett_conn + && !NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + /* + * Either we have a coliding connection, or our connection has been + * modified by user. For the latter case it's safe to leave it alone; + * the UUID will still let it connect. However, for the first case, + * we can't really do anything about it unless we re-write the way we + * track connection <-> context, which I (Ratchanan) don't want to do + * right now... + */ + return; + } + + connection = nm_simple_connection_new(); + setting = nm_setting_connection_new(); + g_object_set(setting, + NM_SETTING_CONNECTION_ID, + context_name, + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, + TRUE, + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_GSM_SETTING_NAME, + NULL); + nm_connection_add_setting(connection, setting); + + setting = nm_setting_gsm_new(); + + /* + * oFono should already know how to handle placing the call, but NM + * insists on having a number. Pass the usual *99#. + */ + g_object_set(setting, NM_SETTING_GSM_NUMBER, "*99#", NULL); + nm_connection_add_setting(connection, setting); + + if (!nm_connection_normalize(connection, NULL, NULL, &error)) { + nm_log_err(LOGD_MB, + "ofono: could not not generate a connection for %s: %s", + context_name, + error->message); + return; + } + + if (!sett_conn) { + nm_settings_add_connection(priv->settings, + NULL, /* plugin */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_ADD_REASON_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + &sett_conn, + &error); + } else { + nm_settings_update_connection(priv->settings, + sett_conn, + NULL, /* plugin_name */ + connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + /* log_context_name */ "ofono", + &error); + } + + if (!sett_conn) { + nm_log_warn(LOGD_MB, + "ofono: could not add or update new connection for '%s' (%s): %s", + context_name, + uuid, + error->message); + return; + } + + g_hash_table_insert(priv->connections, g_strdup(uuid), g_object_ref(sett_conn)); +} + +/* + * Used when we decide a connection is not needed. Rationale being that the + * connection could have been modified by user since it's created by us, + * after which we don't want to delete, but we don't want to track it either. + */ + +static void +untrack_connection_and_delete_if_generated(NMModemOfono *self, char const *uuid) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + NMSettingsConnection *sett_conn; + + sett_conn = g_hash_table_lookup(priv->connections, uuid); + if (!sett_conn) + return; + + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + nm_settings_connection_delete(sett_conn, FALSE); + + g_hash_table_remove(priv->connections, uuid); +} + +static void +update_connection_list(NMModemOfono *self) +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + GHashTableIter iter; + char *uuid; + OfonoContextData *octx; + OfonoContextData *octx_preferred = NULL; + + _LOGI("(re-)checking which context needs a connection"); + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + if (octx->preferred && nm_streq(octx->type, "internet")) { + octx_preferred = octx; + break; + } + } + + g_hash_table_iter_init(&iter, priv->contexts); + while (g_hash_table_iter_next(&iter, (gpointer *) &uuid, (gpointer *) &octx)) { + gboolean connection_should_exist = + octx_preferred == octx || (!octx_preferred && nm_streq(octx->type, "internet")); + gboolean connection_exists = g_hash_table_contains(priv->connections, uuid); + + if (connection_should_exist && !connection_exists) { + _LOGI("creating connection for %s%s", + octx_preferred ? "preferred context " : "", + g_dbus_proxy_get_object_path(octx->proxy)); + add_or_update_connection(self, octx->name, uuid); + } else if (!connection_should_exist && connection_exists) { + _LOGI("removing connection for %s", g_dbus_proxy_get_object_path(octx->proxy)); + untrack_connection_and_delete_if_generated(self, uuid); + + /* priv->current_octx is deliberately not cleared here because the + * disconnection chain happens in another main loop iteration. + */ + } + } +} + +static void handle_settings(NMModemOfono *self, GVariant *v_dict); + +static void +context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self = octx->self; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_unref_variant GVariant *v_inner = g_variant_get_child_value(v, 0); + + if (!v_inner) { + _LOGW("ofono: (%s): error handling PropertyChanged signal", + nm_modem_get_uid(NM_MODEM(self))); + return; + } + + if (nm_streq(property, "Name")) { + gs_free char *uuid = NULL; + + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->name); + octx->name = g_variant_dup_string(v_inner, /* &length */ NULL); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + if (g_hash_table_contains(priv->connections, uuid)) + add_or_update_connection(self, octx->name, uuid); + } else if (nm_streq(property, "Type")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_STRING)); + g_free(octx->type); + octx->type = g_variant_dup_string(v_inner, /* &length */ NULL); + + update_connection_list(self); + } else if (nm_streq(property, "Preferred")) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_BOOLEAN)); + octx->preferred = g_variant_get_boolean(v_inner); + + update_connection_list(self); + } else if (nm_streq(property, "Settings") && priv->current_octx == octx) { + g_return_if_fail(g_variant_is_of_type(v_inner, G_VARIANT_TYPE_VARDICT)); + handle_settings(self, v_inner); + } +} + +static void +_context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + OfonoContextData *octx = user_data; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + char *uuid; + + proxy = g_dbus_proxy_new_for_bus_finish(result, &error); + if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + ofono_context_data_free(octx); + return; + } + + self = octx->self; + priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + if (!proxy) { + _LOGW("failed to create ConnectionContext proxy: %s", error->message); + ofono_context_data_free(octx); + return; + } + + _LOGD("recieved proxy for %s", g_dbus_proxy_get_object_path(proxy)); + octx->proxy = proxy; + + _nm_dbus_proxy_signal_connect(proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(context_property_changed), + octx); + + uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); + g_hash_table_insert(priv->contexts, uuid, octx); + priv->n_context_proxy_pending--; + + if (priv->n_context_proxy_pending == 0) + update_connection_list(self); +} + +static void +connman_context_removed(GDBusProxy *proxy, const char *object_path, gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + gs_free char *uuid = NULL; + OfonoContextData *octx; + + /* look up the connction, and if we have connection disconnect and remove it */ + uuid = _generate_uuid(priv->imsi, object_path); + untrack_connection_and_delete_if_generated(self, uuid); + + octx = g_hash_table_lookup(priv->contexts, uuid); + if (octx) { + gboolean preferred = octx->preferred; + + if (octx == priv->current_octx) + priv->current_octx = NULL; + + g_hash_table_remove(priv->contexts, uuid); + + if (preferred) + update_connection_list(self); + } +} + +static void +connman_context_added(GDBusProxy *proxy, const char *object_path, GVariant *v, gpointer user_data) +{ + NMModemOfono *self = user_data; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + OfonoContextData *octx; + gs_unref_variant GVariant *v_context_type = NULL; + gs_unref_variant GVariant *v_context_name = NULL; + gs_unref_variant GVariant *v_context_preferred = NULL; + + nm_log_info(LOGD_MB, "ofono: processing context %s", object_path); + + v_context_name = g_variant_lookup_value(v, "Name", G_VARIANT_TYPE_STRING); + v_context_type = g_variant_lookup_value(v, "Type", G_VARIANT_TYPE_STRING); + if (!v_context_name || !v_context_type) { + nm_log_err(LOGD_MB, "ofono: context dictionary is missing required key(s)."); + return; + } + + /* Preferred property exists in some oFono fork only (mostly Ubuntu Touch's). */ + v_context_preferred = g_variant_lookup_value(v, "Preferred", G_VARIANT_TYPE_BOOLEAN); + + octx = g_slice_new0(OfonoContextData); + octx->self = self; + octx->name = g_variant_dup_string(v_context_name, NULL); + octx->type = g_variant_dup_string(v_context_type, NULL); + octx->preferred = v_context_preferred && g_variant_get_boolean(v_context_preferred); + + priv->n_context_proxy_pending++; + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + object_path, + OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, + priv->connman_proxy_cancellable, + _context_proxy_new_cb, + octx); +} + +static void +connman_get_contexts_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NMModemOfono *self; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_contexts = NULL; + gs_unref_variant GVariant *v_objects = NULL; + gs_unref_variant GVariant *v = NULL; + GVariantIter i; + const char *object_path; + + v_contexts = _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), + result, + G_VARIANT_TYPE("(a(oa{sv}))"), + &error); + if (!v_contexts && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + + if (!v_contexts) { + g_dbus_error_strip_remote_error(error); + _LOGW("Error getting list of contexts: %s", error->message); + return; + } + + nm_log_info(LOGD_MB, "ofono: printing %s", g_variant_get_type_string(v_contexts)); + + v_objects = g_variant_get_child_value(v_contexts, 0); + + g_variant_iter_init(&i, v_objects); + while (g_variant_iter_loop(&i, "(&o@a{sv})", &object_path, &v)) + connman_context_added(NULL, object_path, v, self); +} + +static void _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) { NMModemOfono *self; @@ -548,11 +972,23 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy = proxy; - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(connman_property_changed), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextAdded", + G_VARIANT_TYPE("(oa{sv})"), + G_CALLBACK(connman_context_added), + self); + + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextRemoved", + G_VARIANT_TYPE("(o)"), + G_CALLBACK(connman_context_removed), + self); g_dbus_proxy_call(priv->connman_proxy, "GetProperties", @@ -562,6 +998,15 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy_cancellable, connman_get_properties_done, self); + + g_dbus_proxy_call(priv->connman_proxy, + "GetContexts", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->connman_proxy_cancellable, + connman_get_contexts_done, + self); } static void @@ -572,6 +1017,9 @@ handle_connman_iface(NMModemOfono *self, gboolean found) _LOGD("ConnectionManager interface %sfound", found ? "" : "not "); if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { + GHashTableIter iter; + NMSettingsConnection *conn; + _LOGI("ConnectionManager interface disappeared"); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); if (priv->connman_proxy) { @@ -584,6 +1032,18 @@ handle_connman_iface(NMModemOfono *self, gboolean found) */ priv->gprs_attached = FALSE; + g_hash_table_iter_init(&iter, priv->connections); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &conn)) { + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { + nm_settings_connection_delete(conn, FALSE); + } + } + + priv->current_octx = NULL; + g_hash_table_remove_all(priv->connections); + g_hash_table_remove_all(priv->contexts); + update_modem_state(self); } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { _LOGI("found new ConnectionManager interface"); @@ -716,7 +1176,7 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) self = NM_MODEM_OFONO(user_data); priv = NM_MODEM_OFONO_GET_PRIVATE(self); - g_clear_object(&priv->context_proxy_cancellable); + g_clear_object(&priv->connect_cancellable); nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); @@ -730,9 +1190,8 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) } static void -handle_settings(GVariant *v_dict, gpointer user_data) +handle_settings(NMModemOfono *self, GVariant *v_dict) { - NMModemOfono *self = NM_MODEM_OFONO(user_data); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMPlatformIP4Address address; @@ -744,14 +1203,20 @@ handle_settings(GVariant *v_dict, gpointer user_data) int ifindex; GError *error = NULL; - //_LOGD("PropertyChanged: %s", property); - /* * TODO: might be a good idea and re-factor this to mimic bluez-device, * ie. have this function just check the key, and call a sub-func to * handle the action. */ + if (nm_modem_get_state(NM_MODEM(self)) < NM_MODEM_STATE_REGISTERED) { + /* + * Connection definitely isn't happening. Avoid trigering bogus + * failure which would put device in a wrong state. + */ + return; + } + _LOGI("IPv4 static Settings:"); if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { @@ -786,7 +1251,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Address' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("can't convert 'Address' %s to addr", s ?: ""); goto out; } @@ -801,11 +1266,11 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Netmask' missing"); goto out; } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (!s || !nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { _LOGW("invalid 'Netmask': %s", s ?: ""); goto out; } - address.plen = _nm_utils_ip4_netmask_to_prefix(address_network); + address.plen = nm_ip4_addr_netmask_to_prefix(address_network); _LOGI("Address: %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); nm_l3_config_data_add_address_4(priv->l3cd_4, &address); @@ -814,7 +1279,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("Settings 'Gateway' missing"); goto out; } - if (!nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &gateway_network)) { + if (!nm_inet_parse_bin(AF_INET, s, NULL, &gateway_network)) { _LOGW("invalid 'Gateway': %s", s); goto out; } @@ -841,14 +1306,13 @@ handle_settings(GVariant *v_dict, gpointer user_data) gsize i; for (i = 0; array[i]; i++) { - if (!nm_utils_parse_inaddr_bin(AF_INET, array[i], NULL, &address_network) - || !address_network) { + if (!nm_inet_parse_bin(AF_INET, array[i], NULL, &address_network) || !address_network) { _LOGW("invalid NameServer: %s", array[i]); continue; } any_good = TRUE; _LOGI("DNS: %s", array[i]); - nm_l3_config_data_add_nameserver(priv->l3cd_4, AF_INET, &address_network); + nm_l3_config_data_add_nameserver_detail(priv->l3cd_4, AF_INET, &address_network, NULL); } if (!any_good) { _LOGW("Settings: 'DomainNameServers': none specified"); @@ -858,7 +1322,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { _LOGI("MessageProxy: %s", s); - if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { + if (s && nm_inet_parse_bin(AF_INET, s, NULL, &address_network)) { const NMPlatformIP4Route mms_route = { .network = address_network, .plen = 32, @@ -893,28 +1357,6 @@ out: } static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono *self = NM_MODEM_OFONO(user_data); - gs_unref_variant GVariant *v_dict = NULL; - - _LOGD("PropertyChanged: %s", property); - - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("ofono: (%s): error getting IPv4 Settings", nm_modem_get_uid(NM_MODEM(self))); - return; - } - - g_assert(g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT)); - - handle_settings(v_dict, user_data); -} - -static void stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_method) { NMModemOfono *self = NM_MODEM_OFONO(modem); @@ -948,17 +1390,13 @@ out: static void context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; + NMModemOfono *self = user_data; gs_free_error GError *error = NULL; gs_unref_variant GVariant *properties = NULL; gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *v_dict = NULL; gboolean active; - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - properties = g_dbus_proxy_call_finish(proxy, result, &error); if (!properties) { @@ -978,13 +1416,6 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - if (active) { _LOGD("ofono: connection is already Active"); @@ -994,9 +1425,9 @@ context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat goto error; } - handle_settings(settings, user_data); + handle_settings(self, settings); } else { - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(proxy, "SetProperty", g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), G_DBUS_CALL_FLAGS_NONE, @@ -1012,36 +1443,15 @@ error: } static void -context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) +do_context_activate(NMModemOfono *self) { - NMModemOfono *self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy *proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); + g_return_if_fail(NM_IS_MODEM_OFONO(self)); - if (!proxy) { - _LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - return; - } + nm_clear_g_cancellable(&priv->connect_cancellable); - priv->context_proxy = proxy; - - if (!priv->gprs_attached) { - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } + priv->connect_cancellable = g_cancellable_new(); /* We have an old copy of the settings from a previous activation, * clear it so that we can gate getting the IP config from oFono @@ -1051,39 +1461,16 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) /* We need to directly query ConnectionContextinteface to get the current * property values */ - g_dbus_proxy_call(priv->context_proxy, + g_dbus_proxy_call(priv->current_octx->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, + priv->connect_cancellable, (GAsyncReadyCallback) context_properties_cb, self); } -static void -do_context_activate(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_return_if_fail(NM_IS_MODEM_OFONO(self)); - - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - g_clear_object(&priv->context_proxy); - - priv->context_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - priv->context_path, - OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - priv->context_proxy_cancellable, - context_proxy_new_cb, - self); -} - static GHashTable * create_connect_properties(NMConnection *connection) { @@ -1109,6 +1496,20 @@ create_connect_properties(NMConnection *connection) return properties; } +static gboolean +wait_for_signal_timeout(gpointer user_data) +{ + NMModemOfono *self = NM_MODEM_OFONO(user_data); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + nm_modem_emit_prepare_result(NM_MODEM(self), + FALSE, + NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + return G_SOURCE_REMOVE; +} + static NMActStageReturn modem_act_stage1_prepare(NMModem *modem, NMConnection *connection, @@ -1116,20 +1517,10 @@ modem_act_stage1_prepare(NMModem *modem, { NMModemOfono *self = NM_MODEM_OFONO(modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char *context_id; - char **id = NULL; + const char *uuid = nm_connection_get_uuid(connection); + OfonoContextData *octx = g_hash_table_lookup(priv->contexts, uuid); - context_id = nm_connection_get_id(connection); - id = g_strsplit(context_id, "/", 0); - g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE); - - _LOGD("trying %s %s", id[1], id[2]); - - g_free(priv->context_path); - priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]); - g_strfreev(id); - - if (!priv->context_path) { + if (!octx) { NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -1139,11 +1530,19 @@ modem_act_stage1_prepare(NMModem *modem, priv->connect_properties = create_connect_properties(connection); - _LOGI("activating context %s", priv->context_path); + _LOGI("activating context %s", g_dbus_proxy_get_object_path(octx->proxy)); + priv->current_octx = octx; update_modem_state(self); if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { do_context_activate(self); + } else if (nm_modem_get_state(modem) == NM_MODEM_STATE_SEARCHING) { + _LOGI("activation deferred while modem is searching for signal."); + + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + priv->deferred_connection_timeout_source = + nm_g_timeout_add_seconds_source(60 /* seconds */, wait_for_signal_timeout, self); + /* update_modem_state() will advance the next step. */ } else { _LOGW("could not activate context: modem is not registered."); NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); @@ -1176,11 +1575,11 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->modem_proxy = proxy; - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->modem_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(modem_property_changed), + self); g_dbus_proxy_call(priv->modem_proxy, "GetProperties", @@ -1196,7 +1595,17 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) static void nm_modem_ofono_init(NMModemOfono *self) -{} +{ + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + priv->modem_proxy_cancellable = g_cancellable_new(); + priv->connections = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref); + priv->contexts = g_hash_table_new_full(nm_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) ofono_context_data_free); + priv->settings = g_object_ref(NM_SETTINGS_GET); +} static void constructed(GObject *object) @@ -1204,8 +1613,6 @@ constructed(GObject *object) NMModemOfono *self = NM_MODEM_OFONO(object); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - priv->modem_proxy_cancellable = g_cancellable_new(); - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, @@ -1257,7 +1664,7 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->modem_proxy_cancellable); nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - nm_clear_g_cancellable(&priv->context_proxy_cancellable); + nm_clear_g_cancellable(&priv->connect_cancellable); nm_clear_g_cancellable(&priv->sim_proxy_cancellable); if (priv->connect_properties) { @@ -1265,6 +1672,16 @@ dispose(GObject *object) priv->connect_properties = NULL; } + if (priv->connections) { + g_hash_table_destroy(priv->connections); + priv->connections = NULL; + } + + if (priv->contexts) { + g_hash_table_destroy(priv->contexts); + priv->contexts = NULL; + } + nm_clear_l3cd(&priv->l3cd_4); if (priv->modem_proxy) { @@ -1277,19 +1694,21 @@ dispose(GObject *object) g_clear_object(&priv->connman_proxy); } - if (priv->context_proxy) { - g_signal_handlers_disconnect_by_data(priv->context_proxy, self); - g_clear_object(&priv->context_proxy); - } - if (priv->sim_proxy) { g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); g_clear_object(&priv->sim_proxy); } + if (priv->settings) { + g_signal_handlers_disconnect_by_data(priv->settings, self); + g_clear_object(&priv->settings); + } + g_free(priv->imsi); priv->imsi = NULL; + nm_clear_g_source_inst(&priv->deferred_connection_timeout_source); + G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object); } diff --git a/src/core/devices/wwan/nm-modem-ofono.h b/src/core/devices/wwan/nm-modem-ofono.h index ebe21023..02ba49ad 100644 --- a/src/core/devices/wwan/nm-modem-ofono.h +++ b/src/core/devices/wwan/nm-modem-ofono.h @@ -8,8 +8,9 @@ #include "nm-modem.h" -#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) -#define NM_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) +#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) +#define NM_MODEM_OFONO(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) #define NM_IS_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_OFONO)) #define NM_MODEM_OFONO_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index a5ee8ce8..0159d351 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -353,6 +353,12 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); NMModemState prev_state = priv->state; + /* Not all modem classes support set_mm_enabled */ + if (!NM_MODEM_GET_CLASS(self)->set_mm_enabled) { + _LOGD("cannot enable modem: not implemented"); + return; + } + if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { _LOGD("cannot enable modem: already enabled"); return; @@ -375,9 +381,7 @@ nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) return; } - /* Not all modem classes support set_mm_enabled */ - if (NM_MODEM_GET_CLASS(self)->set_mm_enabled) - NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); + NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); /* Pre-empt the state change signal */ nm_modem_set_state(self, diff --git a/src/core/devices/wwan/nm-modem.h b/src/core/devices/wwan/nm-modem.h index ca541073..ec001102 100644 --- a/src/core/devices/wwan/nm-modem.h +++ b/src/core/devices/wwan/nm-modem.h @@ -11,7 +11,7 @@ #include "devices/nm-device.h" #define NM_TYPE_MODEM (nm_modem_get_type()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) +#define NM_MODEM(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) #define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM, NMModemClass)) #define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM)) #define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM)) diff --git a/src/core/devices/wwan/nm-wwan-factory.c b/src/core/devices/wwan/nm-wwan-factory.c index 169407c7..1c6d351f 100644 --- a/src/core/devices/wwan/nm-wwan-factory.c +++ b/src/core/devices/wwan/nm-wwan-factory.c @@ -18,7 +18,7 @@ #define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type()) #define NM_WWAN_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) #define NM_WWAN_FACTORY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) #define NM_IS_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WWAN_FACTORY)) diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 805b42d2..1fc2d944 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -84,6 +84,7 @@ typedef struct _NMDhcpClientPrivate { * and is set from l3cd_next. */ const NML3ConfigData *l3cd_curr; + GSource *previous_lease_timeout_source; GSource *no_lease_timeout_source; GSource *watch_source; GBytes *effective_client_id; @@ -240,7 +241,8 @@ nm_dhcp_client_create_l3cd(NMDhcpClient *self) GHashTable * nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); GHashTable *options; GBytes *effective_client_id; @@ -248,27 +250,29 @@ nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys) effective_client_id = nm_dhcp_client_get_effective_client_id(self); if (effective_client_id) { - guint option = NM_IS_IPv4(priv->config.addr_family) ? NM_DHCP_OPTION_DHCP4_CLIENT_ID - : NM_DHCP_OPTION_DHCP6_CLIENT_ID; - gs_free char *str = nm_dhcp_utils_duid_to_string(effective_client_id); + guint option = IS_IPv4 ? NM_DHCP_OPTION_DHCP4_CLIENT_ID : NM_DHCP_OPTION_DHCP6_CLIENT_ID; + gs_free char *str = nm_dhcp_utils_duid_to_string(effective_client_id); /* Note that for the nm-dhcp-helper based plugins (dhclient), the plugin * may send the used client-id/DUID via the environment variables and * overwrite them yet again. */ - if (static_keys) { - nm_dhcp_option_add_option(options, priv->config.addr_family, option, str); - } else { - g_hash_table_insert( - options, - g_strdup(nm_dhcp_option_request_string(priv->config.addr_family, option)), - g_steal_pointer(&str)); - } + nm_dhcp_option_take_option(options, + static_keys, + priv->config.addr_family, + option, + g_steal_pointer(&str)); } return options; } +const NML3ConfigData * +nm_dhcp_client_get_lease(NMDhcpClient *self) +{ + return NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd_curr; +} + /*****************************************************************************/ gboolean @@ -301,11 +305,16 @@ nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) /*****************************************************************************/ static void -_emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) +_emit_notify_data(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) { g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); } +#define _emit_notify(self, _notify_type, ...) \ + _emit_notify_data( \ + (self), \ + &((const NMDhcpClientNotifyData){.notify_type = (_notify_type), __VA_ARGS__})) + /*****************************************************************************/ static void @@ -392,12 +401,7 @@ _no_lease_timeout(gpointer user_data) NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); nm_clear_g_source_inst(&priv->no_lease_timeout_source); - - _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, - })); - + _emit_notify(self, NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT); return G_SOURCE_CONTINUE; } @@ -473,7 +477,7 @@ _acd_complete_on_idle_cb(gpointer user_data) } #define _acd_reglist_data_get(priv, idx) \ - nm_g_array_index_p((priv)->v4.acd.reglist, AcdRegListData, (idx)) + (&nm_g_array_index((priv)->v4.acd.reglist, AcdRegListData, (idx))) static guint _acd_reglist_data_find(NMDhcpClientPrivate *priv, in_addr_t addr_needle) @@ -503,10 +507,10 @@ _acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log) reglist_data = _acd_reglist_data_get(priv, idx); if (do_log) { - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; _LOGD("acd: drop check for address %s (l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", - _nm_utils_inet4_ntop(reglist_data->addr, sbuf_addr), + nm_inet4_ntop(reglist_data->addr, sbuf_addr), NM_HASH_OBFUSCATE_PTR(reglist_data->l3cd)); } @@ -585,7 +589,7 @@ static void _acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; in_addr_t addr; gboolean addr_changed = FALSE; guint idx; @@ -624,7 +628,7 @@ _acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) _LOGD("acd: %s check for address %s (timeout %u msec, l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", addr_changed ? "add" : "update", - _nm_utils_inet4_ntop(addr, sbuf_addr), + nm_inet4_ntop(addr, sbuf_addr), priv->config.v4.acd_timeout_msec, NM_HASH_OBFUSCATE_PTR(priv->l3cd_next)); @@ -711,7 +715,7 @@ gboolean _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; NMIPAddr yiaddr; const NML3AcdAddrInfo *acd_info; @@ -744,7 +748,7 @@ _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr) return TRUE; _LOGD("offered lease rejected: address %s failed ACD check", - _nm_utils_inet4_ntop(yiaddr.addr4, sbuf_addr)); + nm_inet4_ntop(yiaddr.addr4, sbuf_addr)); return FALSE; } @@ -863,6 +867,9 @@ _nm_dhcp_client_notify(NMDhcpClient *self, return; } + if (priv->l3cd_next) + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + nm_l3_config_data_reset(&priv->l3cd_curr, priv->l3cd_next); if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd_curr @@ -883,18 +890,12 @@ _nm_dhcp_client_notify(NMDhcpClient *self, l3_cfg_notify_check_connected(self); - { - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = - { - .l3cd = priv->l3cd_curr, - .accepted = !priv->l3cfg_notify.wait_dhcp_commit, - }, - }; - - _emit_notify(self, ¬ify_data); - } + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = !priv->l3cfg_notify.wait_dhcp_commit, + }); } static void @@ -1010,12 +1011,10 @@ ipv6_lladdr_timeout(gpointer user_data) nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); - _emit_notify( - self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = "timeout reached while waiting for an IPv6 link-local address", - })); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = + "timeout reached while waiting for an IPv6 link-local address"); return G_SOURCE_CONTINUE; } @@ -1027,12 +1026,9 @@ ipv6_dad_timeout(gpointer user_data) nm_clear_g_source_inst(&priv->v6.dad_timeout_source); - _emit_notify( - self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = "timeout reached while waiting for IPv6 DAD to complete", - })); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = "timeout reached while waiting for IPv6 DAD to complete"); return G_SOURCE_CONTINUE; } @@ -1068,35 +1064,33 @@ ipv6_lladdr_find(NMDhcpClient *self) static void ipv6_tentative_addr_check(NMDhcpClient *self, GPtrArray **tentative, - GPtrArray **missing, + GPtrArray **dadfailed, const NMPlatformIP6Address **valid) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); NMDedupMultiIter iter; const NMPlatformIP6Address *addr; - NML3Cfg *l3cfg = priv->config.l3cfg; + NML3Cfg *l3cfg = priv->config.l3cfg; + NMPlatform *platform = nm_l3cfg_get_platform(l3cfg); + int ifindex = nm_l3cfg_get_ifindex(l3cfg); /* For each address in the lease, check whether it's tentative - * in platform. */ + * or dad-failed in platform. */ nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd_curr, &addr) { const NMPlatformIP6Address *pladdr; - NMPObject needle; - - nmp_object_stackinit_id_ip6_address(&needle, nm_l3cfg_get_ifindex(l3cfg), &addr->address); - pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(nm_platform_lookup_obj(nm_l3cfg_get_platform(l3cfg), - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - &needle)); - if (!pladdr) { - /* 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); + + pladdr = nm_platform_ip6_address_get(platform, ifindex, &addr->address); + if ((pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_DADFAILED)) + || (!pladdr && nm_platform_ip6_dadfailed_check(platform, ifindex, &addr->address))) { + if (dadfailed) { + if (!*dadfailed) + *dadfailed = g_ptr_array_new(); + g_ptr_array_add(*dadfailed, (gpointer) addr); } continue; } - if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) + if (pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) { if (tentative) { if (!*tentative) @@ -1105,6 +1099,9 @@ ipv6_tentative_addr_check(NMDhcpClient *self, } } + /* Here the address is non-tentative or it was removed externally by the user. + * In both cases it has completed DAD. + */ NM_SET_OUT(valid, addr); } } @@ -1113,7 +1110,7 @@ static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; nm_assert(l3cfg == priv->config.l3cfg); @@ -1133,10 +1130,8 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp if (!NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, &addr->address, &error)) { _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = error->message, - })); + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = error->message); } } } @@ -1144,13 +1139,13 @@ 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) { gs_unref_ptrarray GPtrArray *tentative = NULL; - gs_unref_ptrarray GPtrArray *missing = NULL; + gs_unref_ptrarray GPtrArray *dadfailed = 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); + ipv6_tentative_addr_check(self, &tentative, &dadfailed, &valid); if (tentative) { for (i = 0; i < tentative->len; i++) { _LOGD("still waiting DAD for address: %s", @@ -1163,10 +1158,10 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp nm_clear_g_source_inst(&priv->v6.dad_timeout_source); l3_cfg_notify_check_connected(self); - if (missing) { - for (i = 0; i < missing->len; i++) { + if (dadfailed) { + for (i = 0; i < dadfailed->len; i++) { _LOGE("DAD failed for address: %s", - nm_platform_ip6_address_to_string(missing->pdata[i], str, sizeof(str))); + nm_platform_ip6_address_to_string(dadfailed->pdata[i], str, sizeof(str))); } } @@ -1176,22 +1171,19 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp 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, - }})); + 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, - })); + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = reason); } } else { _LOGD("decline the lease"); @@ -1266,20 +1258,17 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp _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, - })); + 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_LEASE_UPDATE, - .lease_update = { - .l3cd = priv->l3cd_curr, - .accepted = TRUE, - }})); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = TRUE, + }); } } wait_dhcp_commit_done: @@ -1318,7 +1307,7 @@ wait_dhcp_commit_done: if (acd_state != NM_OPTION_BOOL_DEFAULT) { _LOGD("acd: acd %s for %s", acd_state ? "ready" : "conflict", - _nm_utils_inet4_ntop(priv->v4.acd.addr, sbuf_addr)); + nm_inet4_ntop(priv->v4.acd.addr, sbuf_addr)); nm_l3cfg_commit_type_clear(priv->config.l3cfg, &priv->v4.acd.l3cfg_commit_handle); priv->v4.acd.state = acd_state; priv->v4.acd.done_source = nm_g_idle_add_source(_acd_complete_on_idle_cb, self); @@ -1327,6 +1316,19 @@ wait_dhcp_commit_done: } } +static gboolean +_previous_lease_timeout_cb(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, NULL); + + return G_SOURCE_CONTINUE; +} + gboolean nm_dhcp_client_start(NMDhcpClient *self, GError **error) { @@ -1358,6 +1360,23 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error) _no_lease_timeout_schedule(self); + if (priv->config.previous_lease) { + /* We got passed a previous lease (during a reapply). For a few seconds, we + * will pretend that this is current lease. */ + priv->l3cd_curr = g_steal_pointer(&priv->config.previous_lease); + + /* Schedule a timeout for when we give up using this lease. Note + * that then we will emit a NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE event + * and the lease is gone. Note that NMDevice ignores that and will + * keep using the lease. + * + * At the same time, we have _no_lease_timeout_schedule() ticking, when + * that expires, we will emit a NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT + * signal, which causes NMDevice to clear the lease. */ + priv->previous_lease_timeout_source = + nm_g_timeout_add_seconds_source(15, _previous_lease_timeout_cb, self); + } + if (IS_IPv4) return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); @@ -1438,6 +1457,8 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) if (priv->is_stopped) return; + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + priv->is_stopped = TRUE; if (priv->invocation) { @@ -1567,6 +1588,20 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant str_value = nm_dhcp_utils_duid_to_string(bytes); } + if (!IS_IPv4 && nm_streq(key, "iaid")) { + gs_free char *str = g_steal_pointer(&str_value); + guint32 iaid; + + /* Validate and normalize the iaid. */ + + if (!nm_dhcp_iaid_from_hexstr(str, &iaid)) { + /* Seems invalid. Ignore */ + return; + } + + str_value = nm_dhcp_iaid_to_hexstr(iaid, g_malloc(NM_DHCP_IAID_TO_HEXSTR_BUF_LEN)); + } + g_hash_table_insert(hash, g_strdup(key), str_value); /* dhclient has no special labels for private dhcp options: it uses "unknown_xyz" @@ -1597,15 +1632,11 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self, const NMPlatformIP6Address *prefix) { - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED, - .prefix_delegated = - { - .prefix = prefix, - }, - }; - - _emit_notify(self, ¬ify_data); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED, + .prefix_delegated = { + .prefix = prefix, + }); } gboolean @@ -1621,7 +1652,7 @@ nm_dhcp_client_handle_event(gpointer unused, nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; NMDhcpClientEventType client_event_type; NMPlatformIP6Address prefix = { - 0, + 0, }; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); @@ -1751,14 +1782,14 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) in_addr_t mask; int r_prefix; - if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->config.reject_servers[i], - NULL, - &r_addr, - &r_prefix)) + if (!nm_inet_parse_with_prefix_bin(AF_INET, + priv->config.reject_servers[i], + NULL, + &r_addr, + &r_prefix)) nm_assert_not_reached(); - mask = _nm_utils_ip4_prefix_to_netmask(r_prefix < 0 ? 32 : r_prefix); + mask = nm_ip4_addr_netmask_from_prefix(r_prefix < 0 ? 32 : r_prefix); if ((addr4 & mask) == (r_addr & mask)) return TRUE; } @@ -1783,6 +1814,8 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) g_object_ref(config->l3cfg); + nm_l3_config_data_ref_and_seal(config->previous_lease); + nm_g_bytes_ref(config->hwaddr); nm_g_bytes_ref(config->bcast_hwaddr); nm_g_bytes_ref(config->vendor_class_identifier); @@ -1843,6 +1876,8 @@ config_clear(NMDhcpClientConfig *config) { g_object_unref(config->l3cfg); + nm_clear_l3cd(&config->previous_lease); + nm_clear_pointer(&config->hwaddr, g_bytes_unref); nm_clear_pointer(&config->bcast_hwaddr, g_bytes_unref); nm_clear_pointer(&config->vendor_class_identifier, g_bytes_unref); @@ -1919,6 +1954,7 @@ dispose(GObject *object) watch_cleanup(self); + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); nm_clear_g_source_inst(&priv->no_lease_timeout_source); if (!NM_IS_IPv4(priv->config.addr_family)) { diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 6f403b61..f43770a0 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -14,7 +14,8 @@ #define NM_DHCP_TIMEOUT_INFINITY ((guint32) G_MAXINT32) #define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type()) -#define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) +#define NM_DHCP_CLIENT(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) #define NM_DHCP_CLIENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) #define NM_IS_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_CLIENT)) @@ -91,9 +92,8 @@ typedef struct { * NMDhcpClient is supposed to run. */ NML3Cfg *l3cfg; - /* FIXME(l3cfg:dhcp:previous-lease): most parameters of NMDhcpClient are immutable, - * so to change them (during reapply), we need to create and start - * a new NMDhcpClient instance. + /* Most parameters of NMDhcpClient are immutable, so to change them (during + * reapply), we need to create and start a new NMDhcpClient instance. * * However, while the restart happens, we want to stick to the previous * lease (if any). Allow the caller to provide such a previous lease, @@ -120,7 +120,7 @@ typedef struct { const char *uuid; /* Set to reduce the number of broadcast packets when the - * anycast hardware address of the DHCP service is known. */ + * anycast hardware address of the DHCP service is known. */ const char *anycast_address; /* The hostname or FQDN to send. */ @@ -224,18 +224,7 @@ const NMDhcpClientConfig *nm_dhcp_client_get_config(NMDhcpClient *self); pid_t nm_dhcp_client_get_pid(NMDhcpClient *self); -static inline const NML3ConfigData * -nm_dhcp_client_get_lease(NMDhcpClient *self) -{ - /* FIXME(l3cfg:dhcp:previous-lease): this function returns the currently - * valid, exposed lease. - * - * Note that NMDhcpClient should accept as construct argument a *previous* lease, - * and (if that lease is still valid), pretend that it's good to use. The point is - * so that during reapply we keep using the current address, until a new lease - * was received. */ - return NULL; -} +const NML3ConfigData *nm_dhcp_client_get_lease(NMDhcpClient *self); void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release); diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index e4f40d7c..35b2fb2e 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -43,7 +43,7 @@ _addr_family_to_path_part(int addr_family) #define NM_TYPE_DHCP_DHCLIENT (nm_dhcp_dhclient_get_type()) #define NM_DHCP_DHCLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclient)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclient)) #define NM_DHCP_DHCLIENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclientClass)) #define NM_IS_DHCP_DHCLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCLIENT)) diff --git a/src/core/dhcp/nm-dhcp-dhcpcanon.c b/src/core/dhcp/nm-dhcp-dhcpcanon.c index 87e43fa8..cd42b692 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/core/dhcp/nm-dhcp-dhcpcanon.c @@ -18,7 +18,7 @@ #define NM_TYPE_DHCP_DHCPCANON (nm_dhcp_dhcpcanon_get_type()) #define NM_DHCP_DHCPCANON(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanon)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanon)) #define NM_DHCP_DHCPCANON_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass)) #define NM_IS_DHCP_DHCPCANON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCPCANON)) diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c index 280d9ce6..8d2f928b 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcd.c +++ b/src/core/dhcp/nm-dhcp-dhcpcd.c @@ -23,7 +23,8 @@ /*****************************************************************************/ #define NM_TYPE_DHCP_DHCPCD (nm_dhcp_dhcpcd_get_type()) -#define NM_DHCP_DHCPCD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcd)) +#define NM_DHCP_DHCPCD(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcd)) #define NM_DHCP_DHCPCD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcdClass)) #define NM_IS_DHCP_DHCPCD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCPCD)) diff --git a/src/core/dhcp/nm-dhcp-listener.h b/src/core/dhcp/nm-dhcp-listener.h index 5f3c952c..0818b371 100644 --- a/src/core/dhcp/nm-dhcp-listener.h +++ b/src/core/dhcp/nm-dhcp-listener.h @@ -8,7 +8,7 @@ #define NM_TYPE_DHCP_LISTENER (nm_dhcp_listener_get_type()) #define NM_DHCP_LISTENER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListener)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListener)) #define NM_IS_DHCP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_LISTENER)) #define NM_DHCP_LISTENER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListenerClass)) diff --git a/src/core/dhcp/nm-dhcp-manager.h b/src/core/dhcp/nm-dhcp-manager.h index bbd68236..980a26c9 100644 --- a/src/core/dhcp/nm-dhcp-manager.h +++ b/src/core/dhcp/nm-dhcp-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type()) #define NM_DHCP_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_MANAGER, NMDhcpManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_MANAGER, NMDhcpManager)) #define NM_DHCP_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_MANAGER, NMDhcpManagerClass)) #define NM_IS_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_MANAGER)) diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index df88362e..f36dfb4d 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -36,7 +36,7 @@ #define NM_TYPE_DHCP_NETTOOLS (nm_dhcp_nettools_get_type()) #define NM_DHCP_NETTOOLS(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettools)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettools)) #define NM_DHCP_NETTOOLS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettoolsClass)) #define NM_IS_DHCP_NETTOOLS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_NETTOOLS)) @@ -84,6 +84,11 @@ static void dhcp4_event_pop_all_events_on_idle(NMDhcpNettools *self); /*****************************************************************************/ +#define _add_option(options, option, str) \ + nm_dhcp_option_add_option((options), TRUE, AF_INET, (option), (str)) + +/*****************************************************************************/ + static void set_error_nettools(GError **error, int r, const char *message) { @@ -143,12 +148,12 @@ lease_option_consume_route(const uint8_t **datap, if (!nm_dhcp_lease_data_consume_in_addr(&data, &n_data, &dest)) return FALSE; - plen = _nm_utils_ip4_get_default_prefix0(dest); + plen = nm_ip4_addr_get_default_prefix0(dest); if (plen == 0) return FALSE; } - dest = nm_utils_ip4_address_clear_host_address(dest, plen); + dest = nm_ip4_addr_clear_host_address(dest, plen); if (!nm_dhcp_lease_data_consume_in_addr(&data, &n_data, &gateway)) return FALSE; @@ -239,16 +244,16 @@ lease_parse_address(NMDhcpNettools *self /* for logging context only */, r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, &l_data, &l_data_len); if (r == N_DHCP4_E_UNSET) { - char str1[NM_UTILS_INET_ADDRSTRLEN]; - char str2[NM_UTILS_INET_ADDRSTRLEN]; + char str1[NM_INET_ADDRSTRLEN]; + char str2[NM_INET_ADDRSTRLEN]; /* Some DHCP servers may not set the subnet-mask (issue#1037). * Do the same as the dhclient plugin and use a default. */ - a_plen = _nm_utils_ip4_get_default_prefix(a_address.s_addr); - a_netmask = _nm_utils_ip4_prefix_to_netmask(a_plen); + a_plen = nm_ip4_addr_get_default_prefix(a_address.s_addr); + a_netmask = nm_ip4_addr_netmask_from_prefix(a_plen); _LOGT("missing subnet mask (option 1). Guess %s based on IP address %s", - _nm_utils_inet4_ntop(a_netmask, str1), - _nm_utils_inet4_ntop(a_address.s_addr, str2)); + nm_inet4_ntop(a_netmask, str1), + nm_inet4_ntop(a_address.s_addr, str2)); } else { if (r != 0 || !nm_dhcp_lease_data_parse_in_addr(l_data, @@ -261,31 +266,39 @@ lease_parse_address(NMDhcpNettools *self /* for logging context only */, "could not get netmask from lease"); return FALSE; } - a_plen = _nm_utils_ip4_netmask_to_prefix(a_netmask); - a_netmask = _nm_utils_ip4_prefix_to_netmask(a_plen); + a_plen = nm_ip4_addr_netmask_to_prefix(a_netmask); + a_netmask = nm_ip4_addr_netmask_from_prefix(a_plen); } nm_dhcp_option_add_option_in_addr(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, a_address.s_addr); nm_dhcp_option_add_option_in_addr(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, a_netmask); nm_dhcp_option_add_option_u64(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME, (guint64) a_lifetime); if (a_expiry != G_MAXUINT64) { - nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_EXPIRY, a_expiry); + nm_dhcp_option_add_option_u64(options, + TRUE, + AF_INET, + NM_DHCP_OPTION_DHCP4_NM_EXPIRY, + a_expiry); } n_dhcp4_client_lease_get_siaddr(lease, &a_next_server); if (a_next_server.s_addr != INADDR_ANY) { nm_dhcp_option_add_option_in_addr(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, a_next_server.s_addr); @@ -335,25 +348,25 @@ lease_parse_address_list(NDhcp4ClientLease *lease, nm_str_buf_reset(sbuf); for (; l_data_len > 0; l_data_len -= 4, l_data += 4) { - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; const in_addr_t addr = unaligned_read_ne32(l_data); nm_str_buf_append_required_delimiter(sbuf, ' '); - nm_str_buf_append(sbuf, _nm_utils_inet4_ntop(addr, addr_str)); + nm_str_buf_append(sbuf, nm_inet4_ntop(addr, addr_str)); switch (option) { case NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER: - if (addr == 0 || nm_utils_ip4_address_is_loopback(addr)) { + if (addr == 0 || nm_ip4_addr_is_loopback(addr)) { /* Skip localhost addresses, like also networkd does. * See https://github.com/systemd/systemd/issues/4524. */ nm_dhcp_lease_log_invalid_option(iface, AF_INET, option, "address %s is ignored", - _nm_utils_inet4_ntop(addr, addr_str)); + nm_inet4_ntop(addr, addr_str)); continue; } - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &addr, NULL); break; case NM_DHCP_OPTION_DHCP4_NIS_SERVERS: nm_l3_config_data_add_nis_server(l3cd, addr); @@ -368,7 +381,7 @@ lease_parse_address_list(NDhcp4ClientLease *lease, } } - nm_dhcp_option_add_option(options, AF_INET, option, nm_str_buf_get_str(sbuf)); + _add_option(options, option, nm_str_buf_get_str(sbuf)); } static void @@ -378,8 +391,8 @@ lease_parse_routes(NDhcp4ClientLease *lease, GHashTable *options, NMStrBuf *sbuf) { - char dest_str[NM_UTILS_INET_ADDRSTRLEN]; - char gateway_str[NM_UTILS_INET_ADDRSTRLEN]; + char dest_str[NM_INET_ADDRSTRLEN]; + char gateway_str[NM_INET_ADDRSTRLEN]; in_addr_t dest; in_addr_t gateway; uint8_t plen; @@ -412,8 +425,8 @@ lease_parse_routes(NDhcp4ClientLease *lease, nm_str_buf_reset(sbuf); while (lease_option_consume_route(&l_data, &l_data_len, TRUE, &dest, &plen, &gateway)) { - _nm_utils_inet4_ntop(dest, dest_str); - _nm_utils_inet4_ntop(gateway, gateway_str); + nm_inet4_ntop(dest, dest_str); + nm_inet4_ntop(gateway, gateway_str); nm_str_buf_append_required_delimiter(sbuf, ' '); nm_str_buf_append_printf(sbuf, "%s/%d %s", dest_str, (int) plen, gateway_str); @@ -446,7 +459,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, } has_classless = TRUE; - nm_dhcp_option_add_option(options, AF_INET, option_code, nm_str_buf_get_str(sbuf)); + _add_option(options, option_code, nm_str_buf_get_str(sbuf)); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, &l_data, &l_data_len); @@ -454,8 +467,8 @@ lease_parse_routes(NDhcp4ClientLease *lease, nm_str_buf_reset(sbuf); while (lease_option_consume_route(&l_data, &l_data_len, FALSE, &dest, &plen, &gateway)) { - _nm_utils_inet4_ntop(dest, dest_str); - _nm_utils_inet4_ntop(gateway, gateway_str); + nm_inet4_ntop(dest, dest_str); + nm_inet4_ntop(gateway, gateway_str); nm_str_buf_append_required_delimiter(sbuf, ' '); nm_str_buf_append_printf(sbuf, "%s/%d %s", dest_str, (int) plen, gateway_str); @@ -489,10 +502,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, })); } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, - nm_str_buf_get_str(sbuf)); + _add_option(options, NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, nm_str_buf_get_str(sbuf)); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROUTER, &l_data, &l_data_len); @@ -501,7 +511,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, while (nm_dhcp_lease_data_consume_in_addr(&l_data, &l_data_len, &gateway)) { nm_str_buf_append_required_delimiter(sbuf, ' '); - nm_str_buf_append(sbuf, _nm_utils_inet4_ntop(gateway, gateway_str)); + nm_str_buf_append(sbuf, nm_inet4_ntop(gateway, gateway_str)); if (gateway == 0) { /* silently skip 0.0.0.0 */ @@ -534,10 +544,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, })); } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_ROUTER, - nm_str_buf_get_str(sbuf)); + _add_option(options, NM_DHCP_OPTION_DHCP4_ROUTER, nm_str_buf_get_str(sbuf)); } } @@ -570,6 +577,7 @@ lease_parse_search_domains(NDhcp4ClientLease *lease, nm_l3_config_data_add_search(l3cd, AF_INET, domains[i]); nm_dhcp_option_take_option(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, g_strjoinv(" ", domains)); @@ -598,7 +606,7 @@ lease_parse_private_options(NDhcp4ClientLease *lease, GHashTable *options) continue; option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL); - nm_dhcp_option_take_option(options, AF_INET, i, g_steal_pointer(&option_string)); + nm_dhcp_option_take_option(options, TRUE, AF_INET, i, g_steal_pointer(&option_string)); } } @@ -632,6 +640,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err r = n_dhcp4_client_lease_get_server_identifier(lease, &v_inaddr_s); if (r == 0) { nm_dhcp_option_add_option_in_addr(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, v_inaddr_s.s_addr); @@ -645,6 +654,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err iface, NM_DHCP_OPTION_DHCP4_BROADCAST)) { nm_dhcp_option_add_option_in_addr(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, v_inaddr); @@ -696,10 +706,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err } if (sbuf.len > 0) { - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, - nm_str_buf_get_str(&sbuf)); + _add_option(options, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, nm_str_buf_get_str(&sbuf)); } } @@ -713,7 +720,11 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err iface, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU)) { - nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, v_u16); + nm_dhcp_option_add_option_u64(options, + TRUE, + AF_INET, + NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, + v_u16); nm_l3_config_data_set_mtu(l3cd, v_u16); } @@ -731,7 +742,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err iface, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME)) { - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s); + _add_option(options, NM_DHCP_OPTION_DHCP4_HOST_NAME, s); } } @@ -755,6 +766,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err /* "Its minimum length is 1." */ } else { nm_dhcp_option_add_option_utf8safe_escape(options, + TRUE, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, l_data, @@ -782,10 +794,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err const char *escaped; escaped = nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free); - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - escaped ?: ""); + _add_option(options, NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, escaped ?: ""); nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); @@ -808,7 +817,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &to_free); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str ?: ""); + _add_option(options, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str ?: ""); nm_l3_config_data_set_nis_domain(l3cd, v_str ?: ""); } @@ -820,7 +829,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err -1, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &to_free); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_FILENAME, v_str ?: ""); + _add_option(options, NM_DHCP_OPTION_DHCP4_NM_FILENAME, v_str ?: ""); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME, &l_data, &l_data_len); @@ -837,10 +846,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err l_data_len, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &to_free); - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME, - v_str ?: ""); + _add_option(options, NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME, v_str ?: ""); } lease_parse_address_list(lease, l3cd, iface, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); @@ -868,7 +874,7 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil { struct in_addr a_address; nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; gs_free_error GError *error = NULL; nm_assert(lease); @@ -879,9 +885,7 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil return; nm_str_buf_append(&sbuf, "# This is private data. Do not parse.\n"); - nm_str_buf_append_printf(&sbuf, - "ADDRESS=%s\n", - _nm_utils_inet4_ntop(a_address.s_addr, addr_str)); + nm_str_buf_append_printf(&sbuf, "ADDRESS=%s\n", nm_inet4_ntop(a_address.s_addr, addr_str)); if (!g_file_set_contents(lease_file, nm_str_buf_get_str_unsafe(&sbuf), sbuf.len, &error)) _LOGW("error saving lease to %s: %s", lease_file, error->message); @@ -966,7 +970,7 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(self), &server_id)) { _LOGD("server-id %s is in the reject-list, ignoring", - nm_utils_inet_ntop(AF_INET, &server_id, addr_str)); + nm_inet_ntop(AF_INET, &server_id, addr_str)); return; } @@ -976,8 +980,8 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) } _LOGT("selecting offered lease from %s for %s", - _nm_utils_inet4_ntop(server_id.s_addr, addr_str), - _nm_utils_inet4_ntop(yiaddr.s_addr, addr_str2)); + nm_inet4_ntop(server_id.s_addr, addr_str), + nm_inet4_ntop(yiaddr.s_addr, addr_str2)); r = n_dhcp4_client_lease_select(event->offer.lease); @@ -1340,7 +1344,7 @@ ip4_start(NMDhcpClient *client, GError **error) NULL); nm_parse_env_file(contents, "ADDRESS", &s_addr); if (s_addr) - nm_utils_parse_inaddr_bin(AF_INET, s_addr, NULL, &last_addr); + nm_inet_parse_bin(AF_INET, s_addr, NULL, &last_addr); } if (last_addr.s_addr) { diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c index a5bb06d1..33a9f4ed 100644 --- a/src/core/dhcp/nm-dhcp-options.c +++ b/src/core/dhcp/nm-dhcp-options.c @@ -383,8 +383,14 @@ nm_dhcp_option_find(int addr_family, guint option) /*****************************************************************************/ void -nm_dhcp_option_take_option(GHashTable *options, int addr_family, guint option, char *value) +nm_dhcp_option_take_option(GHashTable *options, + gboolean static_keys, + int addr_family, + guint option, + char *value) { + const char *key; + nm_assert_addr_family(addr_family); nm_assert(value); nm_assert(g_utf8_validate(value, -1, NULL)); @@ -395,19 +401,13 @@ nm_dhcp_option_take_option(GHashTable *options, int addr_family, guint option, c return; } - g_hash_table_insert(options, - (gpointer) nm_dhcp_option_request_string(addr_family, option), - value); -} - -void -nm_dhcp_option_add_option(GHashTable *options, int addr_family, guint option, const char *value) -{ - nm_dhcp_option_take_option(options, addr_family, option, g_strdup(value)); + key = nm_dhcp_option_request_string(addr_family, option), + g_hash_table_insert(options, static_keys ? (gpointer) key : g_strdup(key), value); } void nm_dhcp_option_add_option_utf8safe_escape(GHashTable *options, + gboolean static_keys, int addr_family, guint option, const guint8 *data, @@ -420,13 +420,18 @@ nm_dhcp_option_add_option_utf8safe_escape(GHashTable *options, n_data, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &to_free); - nm_dhcp_option_add_option(options, addr_family, option, escaped ?: ""); + nm_dhcp_option_add_option(options, static_keys, addr_family, option, escaped ?: ""); } void -nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value) +nm_dhcp_option_add_option_u64(GHashTable *options, + gboolean static_keys, + int addr_family, + guint option, + guint64 value) { nm_dhcp_option_take_option(options, + static_keys, addr_family, option, g_strdup_printf("%" G_GUINT64_FORMAT, value)); @@ -434,13 +439,18 @@ nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option void nm_dhcp_option_add_option_in_addr(GHashTable *options, + gboolean static_keys, int addr_family, guint option, in_addr_t value) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; - nm_dhcp_option_add_option(options, addr_family, option, _nm_utils_inet4_ntop(value, sbuf)); + nm_dhcp_option_add_option(options, + static_keys, + addr_family, + option, + nm_inet4_ntop(value, sbuf)); } void diff --git a/src/core/dhcp/nm-dhcp-options.h b/src/core/dhcp/nm-dhcp-options.h index fcc6f9cd..050080d9 100644 --- a/src/core/dhcp/nm-dhcp-options.h +++ b/src/core/dhcp/nm-dhcp-options.h @@ -208,20 +208,38 @@ nm_dhcp_option_request_string(int addr_family, guint option) return nm_dhcp_option_get_name(nm_dhcp_option_find(addr_family, option)); } -void nm_dhcp_option_take_option(GHashTable *options, int addr_family, guint option, char *value); -void -nm_dhcp_option_add_option(GHashTable *options, int addr_family, guint option, const char *value); +void nm_dhcp_option_take_option(GHashTable *options, + gboolean static_keys, + int addr_family, + guint option, + char *value); + +static inline void +nm_dhcp_option_add_option(GHashTable *options, + gboolean static_keys, + int addr_family, + guint option, + const char *value) +{ + nm_dhcp_option_take_option(options, static_keys, addr_family, option, g_strdup(value)); +} + void nm_dhcp_option_add_option_utf8safe_escape(GHashTable *options, + gboolean static_keys, int addr_family, guint option, const guint8 *data, gsize n_data); void nm_dhcp_option_add_option_in_addr(GHashTable *options, + gboolean static_keys, int addr_family, guint option, in_addr_t value); -void -nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value); +void nm_dhcp_option_add_option_u64(GHashTable *options, + gboolean static_keys, + int addr_family, + guint option, + guint64 value); void nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family); GHashTable *nm_dhcp_option_create_options_dict(gboolean static_keys); diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 7ce15d30..6f9312da 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -30,7 +30,7 @@ #define NM_TYPE_DHCP_SYSTEMD (nm_dhcp_systemd_get_type()) #define NM_DHCP_SYSTEMD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemd)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemd)) #define NM_DHCP_SYSTEMD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdClass)) #define NM_IS_DHCP_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_SYSTEMD)) @@ -70,11 +70,13 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) static NML3ConfigData * lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GError **error) { + const NMDhcpClientConfig *config; nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; gs_unref_hashtable GHashTable *options = NULL; struct in6_addr tmp_addr; const struct in6_addr *dns; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; + char iaid_buf[NM_DHCP_IAID_TO_HEXSTR_BUF_LEN]; char **domains; char **ntp_fqdns; const struct in6_addr *ntp_addrs; @@ -84,11 +86,19 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro nm_assert(lease); + config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); + l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self)); options = nm_dhcp_client_create_options_dict(NM_DHCP_CLIENT(self), TRUE); - if (!nm_dhcp_client_get_config(NM_DHCP_CLIENT(self))->v6.info_only) { + nm_dhcp_option_add_option(options, + TRUE, + AF_INET6, + NM_DHCP_OPTION_DHCP6_NM_IAID, + nm_dhcp_iaid_to_hexstr(config->v6.iaid, iaid_buf)); + + if (!config->v6.info_only) { gboolean has_any_addresses = FALSE; uint32_t lft_pref; uint32_t lft_valid; @@ -107,7 +117,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro nm_l3_config_data_add_address_6(l3cd, &address); - _nm_utils_inet6_ntop(&tmp_addr, addr_str); + nm_inet6_ntop(&tmp_addr, addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); has_any_addresses = TRUE; @@ -115,6 +125,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro if (str->len) { nm_dhcp_option_add_option(options, + TRUE, AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, str->str); @@ -133,11 +144,15 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro if (num > 0) { nm_gstring_prepare(&str); for (i = 0; i < num; i++) { - _nm_utils_inet6_ntop(&dns[i], addr_str); + nm_inet6_ntop(&dns[i], addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &dns[i]); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &dns[i], NULL); } - nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DNS_SERVERS, str->str); + nm_dhcp_option_add_option(options, + TRUE, + AF_INET6, + NM_DHCP_OPTION_DHCP6_DNS_SERVERS, + str->str); } num = sd_dhcp6_lease_get_domains(lease, &domains); @@ -147,11 +162,15 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro g_string_append(nm_gstring_add_space_delimiter(str), domains[i]); nm_l3_config_data_add_search(l3cd, AF_INET6, domains[i]); } - nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, str->str); + nm_dhcp_option_add_option(options, + TRUE, + AF_INET6, + NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, + str->str); } if (sd_dhcp6_lease_get_fqdn(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_FQDN, s); + nm_dhcp_option_add_option(options, TRUE, AF_INET6, NM_DHCP_OPTION_DHCP6_FQDN, s); } /* RFC 5908, section 4 states: "This option MUST include one, and only @@ -170,12 +189,16 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro num = sd_dhcp6_lease_get_ntp_addrs(lease, &ntp_addrs); if (num > 0) { for (i = 0; i < num; i++) { - _nm_utils_inet6_ntop(&ntp_addrs[i], addr_str); + nm_inet6_ntop(&ntp_addrs[i], addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); } } if (str->len) { - nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_NTP_SERVER, str->str); + nm_dhcp_option_add_option(options, + TRUE, + AF_INET6, + NM_DHCP_OPTION_DHCP6_NTP_SERVER, + str->str); } nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET6, g_steal_pointer(&options)); diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 1bffb3c4..ca1c0482 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -94,7 +94,7 @@ ip4_process_dhcpcd_rfc3442_routes(const char *iface, l3cd, &((const NMPlatformIP4Route){ .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr), + .network = nm_ip4_addr_clear_host_address(rt_addr, rt_cidr), .plen = rt_cidr, .gateway = rt_route, .pref_src = address, @@ -139,7 +139,7 @@ process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route str_addr = g_strjoin(".", addr[0], addr[1], addr[2], addr[3], NULL); if (inet_pton(AF_INET, str_addr, &tmp_addr) <= 0) return FALSE; - v_network = nm_utils_ip4_address_clear_host_address(tmp_addr, v_plen); + v_network = nm_ip4_addr_clear_host_address(tmp_addr, v_plen); } next_hop = g_strjoin(".", o[0], o[1], o[2], o[3], NULL); @@ -203,9 +203,9 @@ ip4_process_dhclient_rfc3442_routes(const char *iface, _LOG2I(LOGD_DHCP4, iface, " classless static route %s/%d gw %s", - _nm_utils_inet4_ntop(route.network, b1), + nm_inet4_ntop(route.network, b1), route.plen, - _nm_utils_inet4_ntop(route.gateway, b2)); + nm_inet4_ntop(route.gateway, b2)); } } @@ -324,8 +324,8 @@ process_classful_routes(const char *iface, * The Static Routes option (option 33) does not provide a subnet mask * for each route - it is assumed that the subnet mask is implicit in * whatever network number is specified in each route entry */ - route.plen = _nm_utils_ip4_get_default_prefix(rt_addr); - if (rt_addr & ~_nm_utils_ip4_prefix_to_netmask(route.plen)) { + route.plen = nm_ip4_addr_get_default_prefix(rt_addr); + if (rt_addr & ~nm_ip4_addr_netmask_from_prefix(route.plen)) { /* RFC 943: target not "this network"; using host routing */ route.plen = 32; } @@ -337,7 +337,7 @@ process_classful_routes(const char *iface, route.metric_any = TRUE; route.metric = 0; - route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen); + route.network = nm_ip4_addr_clear_host_address(route.network, route.plen); nm_l3_config_data_add_route_4(l3cd, &route); @@ -400,7 +400,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, gboolean gateway_has = FALSE; guint32 gateway = 0; guint8 plen = 0; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; guint32 now; g_return_val_if_fail(options != NULL, NULL); @@ -414,7 +414,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, }; str = g_hash_table_lookup(options, "ip_address"); - if (!str || !nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &addr)) + if (!str || !nm_inet_parse_bin(AF_INET, str, NULL, &addr)) return NULL; if (addr == INADDR_ANY) return NULL; @@ -423,11 +423,11 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, str = g_hash_table_lookup(options, "subnet_mask"); if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) { - plen = _nm_utils_ip4_netmask_to_prefix(tmp_addr); + plen = nm_ip4_addr_netmask_to_prefix(tmp_addr); _LOG2I(LOGD_DHCP4, iface, " plen %d (%s)", plen, str); } else { /* Get default netmask for the IP according to appropriate class. */ - plen = _nm_utils_ip4_get_default_prefix(addr); + plen = nm_ip4_addr_get_default_prefix(addr); _LOG2I(LOGD_DHCP4, iface, " plen %d (default)", plen); } @@ -440,7 +440,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, process_classful_routes(iface, options, l3cd, address.address); if (gateway) { - _LOG2I(LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop(gateway, sbuf)); + _LOG2I(LOGD_DHCP4, iface, " gateway %s", nm_inet4_ntop(gateway, sbuf)); gateway_has = TRUE; } else { /* If the gateway wasn't provided as a classless static route with a @@ -499,7 +499,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &tmp_addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &tmp_addr, NULL); _LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s); } } else @@ -593,7 +593,7 @@ nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) { gs_strfreev char **split_addr = NULL; NMPlatformIP6Address address = { - 0, + 0, }; struct in6_addr tmp_addr; char *str = NULL; @@ -704,7 +704,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) { if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &tmp_addr); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &tmp_addr, NULL); _LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s); } } else diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index 7597f516..1c6d6302 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -88,7 +88,6 @@ test_generic_options(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; const char *const *strarr; - const in_addr_t *ia_arr; guint u; options = fill_table(generic_options, NULL); @@ -115,10 +114,10 @@ test_generic_options(void) g_assert_cmpstr(strarr[0], ==, expected_search1); g_assert_cmpstr(strarr[1], ==, expected_search2); - ia_arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &u); + strarr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &u); g_assert_cmpint(u, ==, 2); - nmtst_assert_ip4_address(ia_arr[0], expected_dns1); - nmtst_assert_ip4_address(ia_arr[1], expected_dns2); + g_assert_cmpstr(strarr[0], ==, expected_dns1); + g_assert_cmpstr(strarr[1], ==, expected_dns2); g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); @@ -285,7 +284,7 @@ test_classless_static_routes_1(void) const char *expected_route2_dest = "10.0.0.0"; const char *expected_route2_gw = "10.17.66.41"; static const Option data[] = { - /* dhclient custom format */ + /* dhclient custom format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, {NULL, NULL}}; @@ -310,7 +309,7 @@ test_classless_static_routes_2(void) const char *expected_route2_dest = "10.0.0.0"; const char *expected_route2_gw = "10.17.66.41"; static const Option data[] = { - /* dhcpcd format */ + /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, {NULL, NULL}}; @@ -336,7 +335,7 @@ test_fedora_dhclient_classless_static_routes(void) const char *expected_route2_gw = "10.34.255.6"; const char *expected_gateway = "192.168.0.113"; static const Option data[] = { - /* Fedora dhclient format */ + /* Fedora dhclient format */ {"classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, {NULL, NULL}}; @@ -362,7 +361,7 @@ test_dhclient_invalid_classless_routes_1(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static const Option data[] = { - /* dhclient format */ + /* dhclient format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, {NULL, NULL}}; @@ -389,7 +388,7 @@ test_dhcpcd_invalid_classless_routes_1(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - /* dhcpcd format */ + /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, {NULL, NULL}}; @@ -419,8 +418,8 @@ test_dhclient_invalid_classless_routes_2(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -448,8 +447,8 @@ test_dhcpcd_invalid_classless_routes_2(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, - {NULL, NULL}}; + {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -477,8 +476,8 @@ test_dhclient_invalid_classless_routes_3(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static const Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -501,8 +500,8 @@ test_dhcpcd_invalid_classless_routes_3(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, - {NULL, NULL}}; + {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -526,8 +525,8 @@ test_dhclient_gw_in_classless_routes(void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -550,8 +549,8 @@ test_dhcpcd_gw_in_classless_routes(void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, - {NULL, NULL}}; + {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index cc7c03a2..05aeff49 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -801,13 +801,13 @@ add_dnsmasq_nameserver(NMDnsDnsmasq *self, g_variant_builder_close(servers); } -#define IP_ADDR_TO_STRING_BUFLEN (NM_UTILS_INET_ADDRSTRLEN + 1 + IFNAMSIZ) +#define IP_ADDR_TO_STRING_BUFLEN (NM_INET_ADDRSTRLEN + 1 + IFNAMSIZ) static const char * ip_addr_to_string(int addr_family, gconstpointer addr, const char *iface, char *out_buf) { int n_written; - char buf2[NM_UTILS_INET_ADDRSTRLEN]; + char buf2[NM_INET_ADDRSTRLEN]; const char *separator; nm_assert_addr_family(addr_family); @@ -815,13 +815,13 @@ ip_addr_to_string(int addr_family, gconstpointer addr, const char *iface, char * nm_assert(out_buf); if (addr_family == AF_INET) { - nm_utils_inet_ntop(addr_family, addr, buf2); + nm_inet_ntop(addr_family, addr, buf2); separator = "@"; } else { if (IN6_IS_ADDR_V4MAPPED(addr)) - _nm_utils_inet4_ntop(((const struct in6_addr *) addr)->s6_addr32[3], buf2); + nm_inet4_ntop(((const struct in6_addr *) addr)->s6_addr32[3], buf2); else - _nm_utils_inet6_ntop(addr, buf2); + nm_inet6_ntop(addr, buf2); /* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58, * only '@' was supported as delimiter. Since 2.58, '@' and '%' are * supported. Due to a bug, since 2.73 only '%' works properly as "server" @@ -868,22 +868,24 @@ add_global_config(NMDnsDnsmasq *self, static void add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsConfigIPData *ip_data) { - const char *iface; - const char *domain; - char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; - gconstpointer nameservers; - guint num; - guint i; - guint j; + const char *iface; + const char *domain; + char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; + const char *const *strarr; + guint num; + guint i; + guint j; iface = nm_platform_link_get_name(NM_PLATFORM_GET, ip_data->data->ifindex); - nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); + strarr = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); for (i = 0; i < num; i++) { - gconstpointer addr; + NMIPAddr a; - addr = nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i); - ip_addr_to_string(ip_data->addr_family, addr, iface, ip_addr_to_string_buf); + if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, NULL)) + continue; + + ip_addr_to_string(ip_data->addr_family, &a, iface, ip_addr_to_string_buf); if (!ip_data->domains.has_default_route_explicit && ip_data->domains.has_default_route) add_dnsmasq_nameserver(self, servers, ip_addr_to_string_buf, NULL); @@ -920,7 +922,8 @@ create_update_args(NMDnsDnsmasq *self, if (global_config) add_global_config(self, &servers, global_config); - else { + + if (!global_config || !nm_global_dns_config_lookup_domain(global_config, "*")) { c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) add_ip_config(self, &servers, ip_data); } diff --git a/src/core/dns/nm-dns-dnsmasq.h b/src/core/dns/nm-dns-dnsmasq.h index 98761d3d..c2f2a115 100644 --- a/src/core/dns/nm-dns-dnsmasq.h +++ b/src/core/dns/nm-dns-dnsmasq.h @@ -10,7 +10,8 @@ #include "nm-dns-manager.h" #define NM_TYPE_DNS_DNSMASQ (nm_dns_dnsmasq_get_type()) -#define NM_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasq)) +#define NM_DNS_DNSMASQ(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasq)) #define NM_DNS_DNSMASQ_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasqClass)) #define NM_IS_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_DNSMASQ)) diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index edb8ce0f..6ee2e816 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -552,29 +552,29 @@ add_dns_domains(GPtrArray *array, static void merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3ConfigData *l3cd) { - char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; + char buf[NM_INET_ADDRSTRLEN + 50]; gboolean has_trust_ad; guint num_nameservers; guint num; guint i; - gconstpointer nameservers; - const char *const *strv; + const char *const *strarr; nm_assert(ifindex == nm_l3_config_data_get_ifindex(l3cd)); - nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers); + strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers); for (i = 0; i < num_nameservers; i++) { - const NMIPAddr *addr; + NMIPAddr a; - addr = nm_ip_addr_from_packed_array(addr_family, nameservers, i); + if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) + continue; if (addr_family == AF_INET) - nm_utils_inet_ntop(addr_family, addr, buf); - else if (IN6_IS_ADDR_V4MAPPED(addr)) - _nm_utils_inet4_ntop(addr->addr6.s6_addr32[3], buf); + nm_inet_ntop(addr_family, &a, buf); + else if (IN6_IS_ADDR_V4MAPPED(&a)) + nm_inet4_ntop(a.addr6.s6_addr32[3], buf); else { - _nm_utils_inet6_ntop(&addr->addr6, buf); - if (IN6_IS_ADDR_LINKLOCAL(addr)) { + nm_inet6_ntop(&a.addr6, buf); + if (IN6_IS_ADDR_LINKLOCAL(&a)) { const char *ifname; ifname = nm_platform_link_get_name(NM_PLATFORM_GET, ifindex); @@ -591,9 +591,9 @@ merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3Con add_dns_domains(rc->searches, addr_family, l3cd, FALSE, TRUE); has_trust_ad = FALSE; - strv = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num); + strarr = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num); for (i = 0; i < num; i++) { - const char *option = strv[i]; + const char *option = strarr[i]; if (nm_streq(option, NM_SETTING_DNS_OPTION_TRUST_AD)) { has_trust_ad = TRUE; @@ -619,7 +619,7 @@ merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3Con nis_servers = nm_l3_config_data_get_nis_servers(l3cd, &num); for (i = 0; i < num; i++) - add_string_item(rc->nis_servers, _nm_utils_inet4_ntop(nis_servers[i], buf), TRUE); + add_string_item(rc->nis_servers, nm_inet4_ntop(nis_servers[i], buf), TRUE); if ((nis_domain = nm_l3_config_data_get_nis_domain(l3cd))) { /* FIXME: handle multiple domains */ @@ -1201,14 +1201,19 @@ compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[ if (global) nm_global_dns_config_update_checksum(global, sum); - else { + + if (!global || !nm_global_dns_config_lookup_domain(global, "*")) { const CList *head; /* FIXME(ip-config-checksum): this relies on the fact that an IP * configuration without DNS parameters gives a zero checksum. */ head = _mgr_get_ip_data_lst_head(self); - c_list_for_each_entry (ip_data, head, ip_data_lst) - nm_ip_config_dns_hash(ip_data->l3cd, sum, ip_data->addr_family); + c_list_for_each_entry (ip_data, head, ip_data_lst) { + nm_l3_config_data_hash_dns(ip_data->l3cd, + sum, + ip_data->addr_family, + ip_data->ip_config_type); + } } nm_utils_checksum_get_digest_len(sum, buffer, HASH_LEN); @@ -1244,13 +1249,15 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) } default_domain = nm_global_dns_config_lookup_domain(global_conf, "*"); - nm_assert(default_domain); + if (!default_domain) + return TRUE; servers = nm_global_dns_domain_get_servers(default_domain); - if (servers) { - for (i = 0; servers[i]; i++) - add_string_item(rc->nameservers, servers[i], TRUE); - } + if (!servers) + return TRUE; + + for (i = 0; servers[i]; i++) + add_string_item(rc->nameservers, servers[i], TRUE); return TRUE; } @@ -1258,19 +1265,21 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) static const char * get_nameserver_list(int addr_family, const NML3ConfigData *l3cd, NMStrBuf *tmp_strbuf) { - char buf[NM_UTILS_INET_ADDRSTRLEN]; - guint num; - guint i; - gconstpointer nameservers; + char buf[NM_INET_ADDRSTRLEN]; + guint num; + guint i; + const char *const *strarr; nm_str_buf_reset(tmp_strbuf); - nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num); + strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num); for (i = 0; i < num; i++) { - const NMIPAddr *addr; + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) + continue; - addr = nm_ip_addr_from_packed_array(addr_family, nameservers, i); - nm_utils_inet_ntop(addr_family, addr->addr_ptr, buf); + nm_inet_ntop(addr_family, &a, buf); if (i > 0) nm_str_buf_append_c(tmp_strbuf, ' '); nm_str_buf_append(tmp_strbuf, buf); @@ -1311,7 +1320,8 @@ _collect_resolv_conf_data(NMDnsManager *self, if (global_config) merge_global_dns_config(&rc, global_config); - else { + + if (!global_config || !nm_global_dns_config_lookup_domain(global_config, "*")) { nm_auto_str_buf NMStrBuf tmp_strbuf = NM_STR_BUF_INIT(0, FALSE); int first_prio = 0; const NMDnsConfigIPData *ip_data; @@ -2090,8 +2100,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s /* Certain hostnames we don't want to include in resolv.conf 'searches' */ if (hostname && nm_utils_is_specific_hostname(hostname) - && !g_str_has_suffix(hostname, ".in-addr.arpa") - && !nm_utils_ipaddr_is_valid(AF_UNSPEC, hostname)) { + && !g_str_has_suffix(hostname, ".in-addr.arpa") && !nm_inet_is_valid(AF_UNSPEC, hostname)) { domain = strchr(hostname, '.'); if (domain) { domain++; @@ -2555,14 +2564,12 @@ config_changed_cb(NMConfig *config, } } -static GVariant * -_get_global_config_variant(NMGlobalDnsConfig *global) +static void +_get_global_config_variant(GVariantBuilder *builder, NMGlobalDnsConfig *global) { NMGlobalDnsDomain *domain; - GVariantBuilder builder; guint i, num; - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); num = nm_global_dns_config_get_num_domains(global); for (i = 0; i < num; i++) { GVariantBuilder conf_builder; @@ -2598,10 +2605,8 @@ _get_global_config_variant(NMGlobalDnsConfig *global) "priority", g_variant_new_int32(NM_DNS_PRIORITY_DEFAULT_NORMAL)); - g_variant_builder_add(&builder, "a{sv}", &conf_builder); + g_variant_builder_add(builder, "a{sv}", &conf_builder); } - - return g_variant_ref_sink(g_variant_builder_end(&builder)); } static GVariant * @@ -2618,28 +2623,25 @@ _get_config_variant(NMDnsManager *self) if (priv->config_variant) return priv->config_variant; - global_config = nm_config_data_get_global_dns_config(nm_config_get_data(priv->config)); - if (global_config) { - priv->config_variant = _get_global_config_variant(global_config); - _LOGT("current configuration: %s", (str = g_variant_print(priv->config_variant, TRUE))); - return priv->config_variant; - } - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); + global_config = nm_config_data_get_global_dns_config(nm_config_get_data(priv->config)); + if (global_config) + _get_global_config_variant(&builder, global_config); + head = _mgr_get_ip_data_lst_head(self); c_list_for_each_entry (ip_data, head, ip_data_lst) { - GVariantBuilder entry_builder; - GVariantBuilder strv_builder; - guint num; - guint num_domains; - guint num_searches; - guint i; - char buf[NM_UTILS_INET_ADDRSTRLEN]; - const char *ifname; - gconstpointer nameservers; - - nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); + GVariantBuilder entry_builder; + GVariantBuilder strv_builder; + guint num; + guint num_domains; + guint num_searches; + guint i; + char buf[NM_INET_ADDRSTRLEN]; + const char *ifname; + const char *const *strarr; + + strarr = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); if (num == 0) continue; @@ -2647,12 +2649,12 @@ _get_config_variant(NMDnsManager *self) g_variant_builder_init(&strv_builder, G_VARIANT_TYPE("as")); for (i = 0; i < num; i++) { - const NMIPAddr *addr; + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, NULL)) + continue; - addr = nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i); - g_variant_builder_add(&strv_builder, - "s", - nm_utils_inet_ntop(ip_data->addr_family, addr, buf)); + g_variant_builder_add(&strv_builder, "s", nm_inet_ntop(ip_data->addr_family, &a, buf)); } g_variant_builder_add(&entry_builder, "{sv}", diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h index 210f9f6c..42f9dec5 100644 --- a/src/core/dns/nm-dns-manager.h +++ b/src/core/dns/nm-dns-manager.h @@ -12,16 +12,6 @@ #include "nm-setting-connection.h" #include "nm-dns-plugin.h" -typedef enum { - NM_DNS_IP_CONFIG_TYPE_REMOVED = -1, - - NM_DNS_IP_CONFIG_TYPE_DEFAULT = 0, - NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, - NM_DNS_IP_CONFIG_TYPE_VPN, -} NMDnsIPConfigType; - -/*****************************************************************************/ - struct _NMDnsConfigData; struct _NMDnsManager; @@ -71,7 +61,7 @@ typedef struct _NMDnsConfigData { /*****************************************************************************/ #define NM_TYPE_DNS_MANAGER (nm_dns_manager_get_type()) -#define NM_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_DNS_MANAGER, NMDnsManager)) +#define NM_DNS_MANAGER(o) (_NM_G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_DNS_MANAGER, NMDnsManager)) #define NM_DNS_MANAGER_CLASS(k) \ (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) #define NM_IS_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), NM_TYPE_DNS_MANAGER)) diff --git a/src/core/dns/nm-dns-plugin.h b/src/core/dns/nm-dns-plugin.h index 24d6083b..364f15ce 100644 --- a/src/core/dns/nm-dns-plugin.h +++ b/src/core/dns/nm-dns-plugin.h @@ -11,7 +11,7 @@ #include "nm-config-data.h" #define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type()) -#define NM_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_PLUGIN, NMDnsPlugin)) +#define NM_DNS_PLUGIN(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_PLUGIN, NMDnsPlugin)) #define NM_DNS_PLUGIN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass)) #define NM_IS_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_PLUGIN)) diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index e0b94647..24c7c774 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -36,6 +36,7 @@ /* define a variable, so that we can compare the operation with pointer equality. */ static const char *const DBUS_OP_SET_LINK_DEFAULT_ROUTE = "SetLinkDefaultRoute"; static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS"; +static const char *const DBUS_OP_SET_LINK_DNS_EX = "SetLinkDNSEx"; /*****************************************************************************/ @@ -90,12 +91,11 @@ typedef struct { bool dbus_initied : 1; bool send_updates_waiting : 1; bool update_pending : 1; - /* These two variables ensure that the log is not spammed with - * API (not) supported messages. - * They can be removed when no distro uses systemd-resolved < v240 anymore - */ - NMTernary has_link_default_route : 3; - NMTernary has_link_dns_over_tls : 3; + + /* Detect support for the respective D-Bus API. */ + NMTernary has_set_link_default_route : 3; + NMTernary has_set_link_dns_over_tls : 3; + NMTernary has_set_link_dns_ex : 3; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -148,6 +148,8 @@ static void _resolve_complete_error(NMDnsSystemdResolvedResolveHandle *handle, G static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResolveHandle *handle); +static void send_updates(NMDnsSystemdResolved *self); + /*****************************************************************************/ static gboolean @@ -276,6 +278,7 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data) NMLogLevel log_level; const char *operation; int ifindex; + gboolean reconfigure = FALSE; request_item = user_data; self = request_item->self; @@ -290,30 +293,52 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data) goto out_dec_pending; if (v) { - if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE - && priv->has_link_default_route == NM_TERNARY_DEFAULT) { - priv->has_link_default_route = NM_TERNARY_TRUE; - _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported"); - } - if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS - && priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT) { - priv->has_link_dns_over_tls = NM_TERNARY_TRUE; - _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API supported"); + if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) { + if (priv->has_set_link_default_route == NM_TERNARY_DEFAULT) { + priv->has_set_link_default_route = NM_TERNARY_TRUE; + _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported"); + } + } else if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) { + if (priv->has_set_link_dns_over_tls == NM_TERNARY_DEFAULT) { + priv->has_set_link_dns_over_tls = NM_TERNARY_TRUE; + _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API supported"); + } + } else if (operation == DBUS_OP_SET_LINK_DNS_EX) { + if (priv->has_set_link_dns_ex == NM_TERNARY_DEFAULT) { + priv->has_set_link_dns_ex = NM_TERNARY_TRUE; + _LOGD("systemd-resolved support for SetLinkDNSEx(): API supported"); + } } priv->send_updates_warn_ratelimited = FALSE; goto out_dec_pending; } if (nm_g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) { - if (priv->has_link_default_route == NM_TERNARY_DEFAULT - && operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) { - priv->has_link_default_route = NM_TERNARY_FALSE; - _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported"); - } - if (priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT - && operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) { - priv->has_link_dns_over_tls = NM_TERNARY_FALSE; - _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API not supported"); + if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) { + if (priv->has_set_link_default_route == NM_TERNARY_DEFAULT) { + priv->has_set_link_default_route = NM_TERNARY_FALSE; + _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported"); + } + } else if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) { + if (priv->has_set_link_dns_over_tls == NM_TERNARY_DEFAULT) { + priv->has_set_link_dns_over_tls = NM_TERNARY_FALSE; + _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API not supported"); + } + } else if (operation == DBUS_OP_SET_LINK_DNS_EX) { + if (priv->has_set_link_dns_ex == NM_TERNARY_DEFAULT) { + priv->has_set_link_dns_ex = NM_TERNARY_FALSE; + _LOGD("systemd-resolved support for SetLinkDNSEx(): API not supported"); + + _LOGW("systemd-resolved does not support SetLinkDNSEx API (v246). " + "Cannot set DoT server name (SNI)"); + + /* We need to reconfigure with the SetLinkDNS fallback. + * + * In the other cases above, there is no need to reconfigure anything. + * We won't retry SetLinkDefaultRoute/SetLinkDNSOverTLS anymore, but there + * is nothing else we can do about that. */ + reconfigure = TRUE; + } } goto out_dec_pending; } @@ -335,21 +360,29 @@ out_dec_pending: * we must wrap up fast, and not hang an undefined amount time. */ g_object_unref(self); } + + if (reconfigure) { + priv->send_updates_waiting = TRUE; + send_updates(self); + } } static gboolean update_add_ip_config(NMDnsSystemdResolved *self, + const NMDnsConfigIPData *ip_data, GVariantBuilder *dns, + GVariantBuilder *dns_ex, GVariantBuilder *domains, - const NMDnsConfigIPData *ip_data) + gboolean *out_require_dns_ex) { - gsize addr_size; - guint n; - guint i; - gboolean is_routing; - const char *domain; - gboolean has_config = FALSE; - gconstpointer nameservers; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + gsize addr_size; + guint n; + guint i; + gboolean is_routing; + const char *domain; + gboolean has_config = FALSE; + const char *const *strarr; addr_size = nm_utils_addr_family_to_size(ip_data->addr_family); @@ -361,29 +394,52 @@ update_add_ip_config(NMDnsSystemdResolved *self, return FALSE; } - nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n); + strarr = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n); for (i = 0; i < n; i++) { - g_variant_builder_open(dns, G_VARIANT_TYPE("(iay)")); - g_variant_builder_add(dns, "i", ip_data->addr_family); - g_variant_builder_add_value( - dns, - nm_g_variant_new_ay(nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i), - addr_size)); - g_variant_builder_close(dns); - has_config = TRUE; - } + const char *server_name; + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, &server_name)) + continue; - if (!ip_data->domains.has_default_route_explicit - && ip_data->domains.has_default_route_exclusive) { - g_variant_builder_add(domains, "(sb)", ".", TRUE); + if (server_name) { + NM_SET_OUT(out_require_dns_ex, TRUE); + if (priv->has_set_link_dns_ex == FALSE) { + /* The caller won't care about this result anymore. We can skip setting it. */ + dns = NULL; + } + } + + if (dns_ex) { + g_variant_builder_open(dns_ex, G_VARIANT_TYPE("(iayqs)")); + g_variant_builder_add(dns_ex, "i", ip_data->addr_family); + g_variant_builder_add_value(dns_ex, nm_g_variant_new_ay((gconstpointer) &a, addr_size)); + g_variant_builder_add(dns_ex, "q", 0); + g_variant_builder_add(dns_ex, "s", server_name ?: ""); + g_variant_builder_close(dns_ex); + } + if (dns) { + g_variant_builder_open(dns, G_VARIANT_TYPE("(iay)")); + g_variant_builder_add(dns, "i", ip_data->addr_family); + g_variant_builder_add_value(dns, nm_g_variant_new_ay((gconstpointer) &a, addr_size)); + g_variant_builder_close(dns); + } has_config = TRUE; } - if (ip_data->domains.search) { - for (i = 0; ip_data->domains.search[i]; i++) { - domain = nm_utils_parse_dns_domain(ip_data->domains.search[i], &is_routing); - g_variant_builder_add(domains, "(sb)", domain[0] ? domain : ".", is_routing); + + if (!has_config || domains) { + if (!ip_data->domains.has_default_route_explicit + && ip_data->domains.has_default_route_exclusive) { + g_variant_builder_add(domains, "(sb)", ".", TRUE); has_config = TRUE; } + if (ip_data->domains.search) { + for (i = 0; ip_data->domains.search[i]; i++) { + domain = nm_utils_parse_dns_domain(ip_data->domains.search[i], &is_routing); + g_variant_builder_add(domains, "(sb)", domain[0] ? domain : ".", is_routing); + has_config = TRUE; + } + } } return has_config; @@ -406,7 +462,9 @@ free_pending_updates(NMDnsSystemdResolved *self) static gboolean prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) { + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); GVariantBuilder dns; + GVariantBuilder dns_ex; GVariantBuilder domains; NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; @@ -417,6 +475,9 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) gboolean has_config = FALSE; gboolean has_default_route = FALSE; guint i; + gboolean require_dns_ex = FALSE; + + nm_assert(ic->ifindex != NM_LOOPBACK_IFINDEX); g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))")); g_variant_builder_add(&dns, "i", ic->ifindex); @@ -430,7 +491,7 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) for (i = 0; i < ic->ip_data_list->len; i++) { const NMDnsConfigIPData *ip_data = ic->ip_data_list->pdata[i]; - if (update_add_ip_config(self, &dns, &domains, ip_data)) + if (update_add_ip_config(self, ip_data, &dns, NULL, &domains, &require_dns_ex)) has_config = TRUE; if (ip_data->domains.has_default_route) @@ -448,6 +509,23 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) g_variant_builder_close(&dns); g_variant_builder_close(&domains); + if (!require_dns_ex) { + /* No need to use the new API. SetLinkDNS() is sufficient. */ + } else if (!priv->has_set_link_dns_ex) { + /* API to set server name is not supported. Nothing we can do. */ + require_dns_ex = FALSE; + } else { + g_variant_builder_init(&dns_ex, G_VARIANT_TYPE("(ia(iayqs))")); + g_variant_builder_add(&dns_ex, "i", ic->ifindex); + g_variant_builder_open(&dns_ex, G_VARIANT_TYPE("a(iayqs)")); + for (i = 0; i < ic->ip_data_list->len; i++) { + const NMDnsConfigIPData *ip_data = ic->ip_data_list->pdata[i]; + + update_add_ip_config(self, ip_data, NULL, &dns_ex, NULL, NULL); + } + g_variant_builder_close(&dns_ex); + } + switch (mdns) { case NM_SETTING_CONNECTION_MDNS_NO: mdns_arg = "no"; @@ -513,7 +591,14 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) "SetLinkLLMNR", ic->ifindex, g_variant_new("(is)", ic->ifindex, llmnr_arg ?: "")); - _request_item_append(self, "SetLinkDNS", ic->ifindex, g_variant_builder_end(&dns)); + if (require_dns_ex) { + _request_item_append(self, + DBUS_OP_SET_LINK_DNS_EX, + ic->ifindex, + g_variant_builder_end(&dns_ex)); + g_variant_builder_clear(&dns); + } else + _request_item_append(self, "SetLinkDNS", ic->ifindex, g_variant_builder_end(&dns)); _request_item_append(self, DBUS_OP_SET_LINK_DNS_OVER_TLS, ic->ifindex, @@ -631,9 +716,9 @@ send_updates(NMDnsSystemdResolved *self) gs_free char *ss = NULL; if ((request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE - && priv->has_link_default_route == NM_TERNARY_FALSE) + && priv->has_set_link_default_route == NM_TERNARY_FALSE) || (request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS - && priv->has_link_dns_over_tls == NM_TERNARY_FALSE)) { + && priv->has_set_link_dns_over_tls == NM_TERNARY_FALSE)) { /* The "SetLinkDefaultRoute" API is only supported since v240. * The "SetLinkDNSOverTLS" API is only supported since v239. * We detected whether they are supported, and skip the calls. There @@ -708,6 +793,13 @@ update(NMDnsPlugin *plugin, nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd)); + if (ifindex == NM_LOOPBACK_IFINDEX) { + /* systemd-resolved API is per-link, and loopback is not supported. + * Unclear what to do about DNS configuration on loopback. Just skip + * it here. */ + continue; + } + ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex)); if (!ic) { ic = g_slice_new(InterfaceConfig); @@ -759,7 +851,7 @@ update(NMDnsPlugin *plugin, if (dirty_array) { g_array_sort_with_data(dirty_array, nm_cmp_int2ptr_p_with_data, NULL); for (i = 0; i < dirty_array->len; i++) { - int ifindex = g_array_index(dirty_array, int, i); + int ifindex = nm_g_array_index(dirty_array, int, i); InterfaceConfig ic; _LOGT("clear previously configured ifindex %d", ifindex); @@ -798,8 +890,9 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) priv->try_start_blocked = FALSE; priv->send_updates_waiting = TRUE; } else { - priv->has_link_default_route = NM_TERNARY_DEFAULT; - priv->has_link_dns_over_tls = NM_TERNARY_DEFAULT; + priv->has_set_link_default_route = NM_TERNARY_DEFAULT; + priv->has_set_link_dns_over_tls = NM_TERNARY_DEFAULT; + priv->has_set_link_dns_ex = NM_TERNARY_DEFAULT; } send_updates(self); @@ -968,7 +1061,7 @@ _resolve_handle_call_cb(GObject *source, GAsyncResult *result, gpointer user_dat g_variant_iter_free(v_names_iter); _resolve_complete(handle, - &g_array_index(v_names, NMDnsSystemdResolvedAddressResult, 0), + nm_g_array_first_p(v_names, NMDnsSystemdResolvedAddressResult), v_names->len, v_flags, NULL); @@ -1066,7 +1159,7 @@ nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); NMDnsSystemdResolvedResolveHandle *handle; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; g_return_val_if_fail(NM_IS_DNS_SYSTEMD_RESOLVED(self), NULL); nm_assert_addr_family(addr_family); @@ -1092,7 +1185,7 @@ nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved _LOG2T(handle, "resolve-address(ifindex=%d, %s, flags=%" G_GINT64_MODIFIER "x): new request", handle->r_address.ifindex, - nm_utils_inet_ntop(handle->r_address.addr_family, &handle->r_address.addr, addr_str), + nm_inet_ntop(handle->r_address.addr_family, &handle->r_address.addr, addr_str), handle->r_address.flags); _resolve_start(self, handle); @@ -1158,8 +1251,9 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - priv->has_link_default_route = NM_TERNARY_DEFAULT; - priv->has_link_dns_over_tls = NM_TERNARY_DEFAULT; + priv->has_set_link_default_route = NM_TERNARY_DEFAULT; + priv->has_set_link_dns_over_tls = NM_TERNARY_DEFAULT; + priv->has_set_link_dns_ex = NM_TERNARY_DEFAULT; c_list_init(&priv->request_queue_lst_head); c_list_init(&priv->handle_lst_head); diff --git a/src/core/dns/nm-dns-systemd-resolved.h b/src/core/dns/nm-dns-systemd-resolved.h index 02bc524c..0563a70f 100644 --- a/src/core/dns/nm-dns-systemd-resolved.h +++ b/src/core/dns/nm-dns-systemd-resolved.h @@ -12,7 +12,7 @@ #define NM_TYPE_DNS_SYSTEMD_RESOLVED (nm_dns_systemd_resolved_get_type()) #define NM_DNS_SYSTEMD_RESOLVED(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_SYSTEMD_RESOLVED, NMDnsSystemdResolved)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_SYSTEMD_RESOLVED, NMDnsSystemdResolved)) #define NM_DNS_SYSTEMD_RESOLVED_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_SYSTEMD_RESOLVED, NMDnsSystemdResolvedClass)) #define NM_IS_DNS_SYSTEMD_RESOLVED(obj) \ diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.c b/src/core/dnsmasq/nm-dnsmasq-manager.c index be463da3..d245d5d3 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.c +++ b/src/core/dnsmasq/nm-dnsmasq-manager.c @@ -104,7 +104,6 @@ create_dm_cmd_line(const char *iface, gs_free char *error_desc = NULL; const char *dm_binary; const NMPlatformIP4Address *listen_address; - const in_addr_t *ipv4arr; const char *const *strarr; guint n; guint i; @@ -147,7 +146,7 @@ create_dm_cmd_line(const char *iface, */ nm_strv_ptrarray_add_string_dup(cmd, "--strict-order"); - _nm_utils_inet4_ntop(listen_address->address, listen_address_s); + nm_inet4_ntop(listen_address->address, listen_address_s); nm_strv_ptrarray_add_string_concat(cmd, "--listen-address=", listen_address_s); @@ -163,13 +162,18 @@ create_dm_cmd_line(const char *iface, nm_strv_ptrarray_add_string_concat(cmd, "--dhcp-option=option:router,", listen_address_s); } - ipv4arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &n); + strarr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &n); if (n > 0) { nm_gstring_prepare(&s); g_string_append(s, "--dhcp-option=option:dns-server"); for (i = 0; i < n; i++) { + in_addr_t a; + + if (!nm_utils_dnsname_parse_assert(AF_INET, strarr[i], NULL, &a, NULL)) + continue; + g_string_append_c(s, ','); - g_string_append(s, _nm_utils_inet4_ntop(ipv4arr[i], sbuf_addr)); + g_string_append(s, nm_inet4_ntop(a, sbuf_addr)); } nm_strv_ptrarray_take_gstring(cmd, &s); } diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.h b/src/core/dnsmasq/nm-dnsmasq-manager.h index 7fd4199e..2f10a9e8 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.h +++ b/src/core/dnsmasq/nm-dnsmasq-manager.h @@ -8,7 +8,7 @@ #define NM_TYPE_DNSMASQ_MANAGER (nm_dnsmasq_manager_get_type()) #define NM_DNSMASQ_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNSMASQ_MANAGER, NMDnsMasqManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNSMASQ_MANAGER, NMDnsMasqManager)) #define NM_DNSMASQ_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNSMASQ_MANAGER, NMDnsMasqManagerClass)) #define NM_IS_DNSMASQ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNSMASQ_MANAGER)) diff --git a/src/core/dnsmasq/nm-dnsmasq-utils.c b/src/core/dnsmasq/nm-dnsmasq-utils.c index 7f799878..69424d74 100644 --- a/src/core/dnsmasq/nm-dnsmasq-utils.c +++ b/src/core/dnsmasq/nm-dnsmasq-utils.c @@ -50,7 +50,7 @@ nm_dnsmasq_utils_get_range(const NMPlatformIP4Address *addr, prefix = 24; } - netmask = _nm_utils_ip4_prefix_to_netmask(prefix); + netmask = nm_ip4_addr_netmask_from_prefix(prefix); /* treat addresses in host-order from here on. */ netmask = ntohl(netmask); @@ -96,8 +96,8 @@ nm_dnsmasq_utils_get_range(const NMPlatformIP4Address *addr, first = htonl(first); last = htonl(last); - _nm_utils_inet4_ntop(first, out_first); - _nm_utils_inet4_ntop(last, out_last); + nm_inet4_ntop(first, out_first); + nm_inet4_ntop(last, out_last); return TRUE; } diff --git a/src/core/main-utils.c b/src/core/main-utils.c index 444e122e..c6fa05c0 100644 --- a/src/core/main-utils.c +++ b/src/core/main-utils.c @@ -18,6 +18,7 @@ #include "main-utils.h" #include "NetworkManagerUtils.h" #include "nm-config.h" +#include "libnm-glib-aux/nm-io-utils.h" static gboolean sighup_handler(gpointer user_data) @@ -76,34 +77,20 @@ nm_main_utils_setup_signals(GMainLoop *main_loop) gboolean nm_main_utils_write_pidfile(const char *pidfile) { - char pid[16]; - int fd; - int errsv; - gboolean success = FALSE; + gs_free_error GError *error = NULL; + char pid[16]; - if ((fd = open(pidfile, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 00644)) < 0) { - errsv = errno; - fprintf(stderr, _("Opening %s failed: %s\n"), pidfile, nm_strerror_native(errsv)); + nm_sprintf_buf(pid, "%lld", (long long) getpid()); + if (!nm_utils_file_set_contents(pidfile, pid, -1, 00644, NULL, NULL, &error)) { + fprintf(stderr, _("Writing to %s failed: %s\n"), pidfile, error->message); return FALSE; } - g_snprintf(pid, sizeof(pid), "%d", getpid()); - if (write(fd, pid, strlen(pid)) < 0) { - errsv = errno; - fprintf(stderr, _("Writing to %s failed: %s\n"), pidfile, nm_strerror_native(errsv)); - } else - success = TRUE; - - if (nm_close(fd)) { - errsv = errno; - fprintf(stderr, _("Closing %s failed: %s\n"), pidfile, nm_strerror_native(errsv)); - } - - return success; + return TRUE; } void -nm_main_utils_ensure_statedir() +nm_main_utils_ensure_statedir(void) { gs_free char *parent = NULL; int errsv; @@ -129,7 +116,7 @@ nm_main_utils_ensure_statedir() } void -nm_main_utils_ensure_rundir() +nm_main_utils_ensure_rundir(void) { int errsv; diff --git a/src/core/meson.build b/src/core/meson.build index f3359ad0..6c1d463e 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -53,6 +53,7 @@ libNetworkManagerBase = static_library( 'nm-l3-ipv4ll.c', 'nm-l3-ipv6ll.c', 'nm-l3cfg.c', + 'nm-bond-manager.c', 'nm-ip-config.c', ), dependencies: [ @@ -103,6 +104,7 @@ libNetworkManager = static_library( 'devices/nm-device-generic.c', 'devices/nm-device-infiniband.c', 'devices/nm-device-ip-tunnel.c', + 'devices/nm-device-loopback.c', 'devices/nm-device-macsec.c', 'devices/nm-device-macvlan.c', 'devices/nm-device-ppp.c', @@ -204,6 +206,7 @@ if enable_tests libnm_core_aux_intern, libnm_core_impl, libnm_crypto, + libnm_lldp, libnm_platform, libnm_base, libnm_systemd_shared, @@ -255,6 +258,7 @@ NetworkManager_all_sym = executable( libnm_core_aux_intern, libnm_core_impl, libnm_crypto, + libnm_lldp, libnm_platform, libnm_base, libnm_log_core, @@ -295,6 +299,7 @@ NetworkManager = executable( libnm_core_aux_intern, libnm_core_impl, libnm_crypto, + libnm_lldp, libnm_platform, libnm_base, libnm_udev_aux, diff --git a/src/core/ndisc/nm-fake-ndisc.c b/src/core/ndisc/nm-fake-ndisc.c index 59bf0c1b..f305e771 100644 --- a/src/core/ndisc/nm-fake-ndisc.c +++ b/src/core/ndisc/nm-fake-ndisc.c @@ -247,14 +247,14 @@ receive_ra(gpointer user_data) } for (i = 0; i < ra->gateways->len; i++) { - const NMNDiscGateway *item = &g_array_index(ra->gateways, NMNDiscGateway, i); + const NMNDiscGateway *item = &nm_g_array_index(ra->gateways, NMNDiscGateway, i); if (nm_ndisc_add_gateway(ndisc, item, now_msec)) changed |= NM_NDISC_CONFIG_GATEWAYS; } for (i = 0; i < ra->prefixes->len; i++) { - FakePrefix *item = &g_array_index(ra->prefixes, FakePrefix, i); + FakePrefix *item = &nm_g_array_index(ra->prefixes, FakePrefix, i); const NMNDiscRoute route = { .network = item->network, .plen = item->plen, @@ -282,14 +282,14 @@ receive_ra(gpointer user_data) } for (i = 0; i < ra->dns_servers->len; i++) { - const NMNDiscDNSServer *item = &g_array_index(ra->dns_servers, NMNDiscDNSServer, i); + const NMNDiscDNSServer *item = &nm_g_array_index(ra->dns_servers, NMNDiscDNSServer, i); if (nm_ndisc_add_dns_server(ndisc, item, now_msec)) changed |= NM_NDISC_CONFIG_DNS_SERVERS; } for (i = 0; i < ra->dns_domains->len; i++) { - const NMNDiscDNSDomain *item = &g_array_index(ra->dns_domains, NMNDiscDNSDomain, i); + const NMNDiscDNSDomain *item = &nm_g_array_index(ra->dns_domains, NMNDiscDNSDomain, i); if (nm_ndisc_add_dns_domain(ndisc, item, now_msec)) changed |= NM_NDISC_CONFIG_DNS_DOMAINS; diff --git a/src/core/ndisc/nm-fake-ndisc.h b/src/core/ndisc/nm-fake-ndisc.h index 91c2c21c..a4a29d7c 100644 --- a/src/core/ndisc/nm-fake-ndisc.h +++ b/src/core/ndisc/nm-fake-ndisc.h @@ -9,7 +9,7 @@ #include "nm-ndisc.h" #define NM_TYPE_FAKE_NDISC (nm_fake_ndisc_get_type()) -#define NM_FAKE_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FAKE_NDISC, NMFakeNDisc)) +#define NM_FAKE_NDISC(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FAKE_NDISC, NMFakeNDisc)) #define NM_FAKE_NDISC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_FAKE_NDISC, NMFakeNDiscClass)) #define NM_IS_FAKE_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_FAKE_NDISC)) diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index 313756a6..63dde5a5 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -202,9 +202,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) r_plen = ndp_msg_opt_prefix_len(msg, offset); if (r_plen == 0 || r_plen > 128) continue; - nm_utils_ip6_address_clear_host_address(&r_network, - ndp_msg_opt_prefix(msg, offset), - r_plen); + nm_ip6_addr_clear_host_address(&r_network, ndp_msg_opt_prefix(msg, offset), r_plen); if (IN6_IS_ADDR_UNSPECIFIED(&r_network) || IN6_IS_ADDR_LINKLOCAL(&r_network)) continue; @@ -213,6 +211,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) const NMNDiscRoute route = { .network = r_network, .plen = r_plen, + .on_link = TRUE, .expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_prefix_valid_time(msg, offset)), @@ -244,15 +243,14 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (plen == 0 || plen > 128) continue; - nm_utils_ip6_address_clear_host_address(&network, - ndp_msg_opt_route_prefix(msg, offset), - plen); + nm_ip6_addr_clear_host_address(&network, ndp_msg_opt_route_prefix(msg, offset), plen); { const NMNDiscRoute route = { .network = network, .gateway = gateway_addr, .plen = plen, + .on_link = FALSE, .expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_route_lifetime(msg, offset)), .preference = _route_preference_coerce(ndp_msg_opt_route_preference(msg, offset)), @@ -417,7 +415,7 @@ send_ra(NMNDisc *ndisc, GError **error) /* The device let us know about all addresses that the device got * whose prefixes are suitable for delegating. Let's announce them. */ for (i = 0; i < rdata->addresses->len; i++) { - const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, i); + const NMNDiscAddress *address = &nm_g_array_index(rdata->addresses, NMNDiscAddress, i); struct nd_opt_prefix_info *prefix; prefix = _ndp_msg_add_option(msg, sizeof(*prefix)); @@ -462,7 +460,7 @@ send_ra(NMNDisc *ndisc, GError **error) for (i = 0; i < rdata->dns_servers->len; i++) { const NMNDiscDNSServer *dns_server = - &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); + &nm_g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); option->addrs[i] = dns_server->address; } @@ -478,7 +476,7 @@ dns_servers_done: for (i = 0; i < rdata->dns_domains->len; i++) { const NMNDiscDNSDomain *dns_domain = - &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); + &nm_g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); const char *domain = dns_domain->domain; gsize domain_l; gsize n_reserved; diff --git a/src/core/ndisc/nm-lndp-ndisc.h b/src/core/ndisc/nm-lndp-ndisc.h index 711a95e1..62b7b217 100644 --- a/src/core/ndisc/nm-lndp-ndisc.h +++ b/src/core/ndisc/nm-lndp-ndisc.h @@ -10,7 +10,7 @@ #include "nm-core-utils.h" #define NM_TYPE_LNDP_NDISC (nm_lndp_ndisc_get_type()) -#define NM_LNDP_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LNDP_NDISC, NMLndpNDisc)) +#define NM_LNDP_NDISC(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LNDP_NDISC, NMLndpNDisc)) #define NM_LNDP_NDISC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_LNDP_NDISC, NMLndpNDiscClass)) #define NM_IS_LNDP_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_LNDP_NDISC)) diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 9a6038d4..39a4df48 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -13,6 +13,7 @@ #include "libnm-platform/nm-platform-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "nm-l3-config-data.h" #include "nm-l3cfg.h" #include "nm-ndisc-private.h" @@ -160,8 +161,9 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, .table_any = TRUE, .table_coerced = 0, .metric_any = TRUE, - .metric = 0, - .rt_pref = ndisc_route->preference, + /* Non-on_link routes get a small penalty */ + .metric = ndisc_route->duplicate && !ndisc_route->on_link ? 5 : 0, + .rt_pref = ndisc_route->preference, }; nm_assert((NMIcmpv6RouterPref) r.rt_pref == ndisc_route->preference); @@ -186,8 +188,12 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, } } - for (i = 0; i < rdata->dns_servers_n; i++) - nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &rdata->dns_servers[i].address); + for (i = 0; i < rdata->dns_servers_n; i++) { + nm_l3_config_data_add_nameserver_detail(l3cd, + AF_INET6, + &rdata->dns_servers[i].address, + NULL); + } for (i = 0; i < rdata->dns_domains_n; i++) nm_l3_config_data_add_search(l3cd, AF_INET6, rdata->dns_domains[i].domain); @@ -324,11 +330,11 @@ _ASSERT_data_gateways(const NMNDiscDataInternal *data) return; for (i = 0; i < data->gateways->len; i++) { - const NMNDiscGateway *item = &g_array_index(data->gateways, NMNDiscGateway, i); + const NMNDiscGateway *item = &nm_g_array_index(data->gateways, NMNDiscGateway, i); nm_assert(!IN6_IS_ADDR_UNSPECIFIED(&item->address)); for (j = 0; j < i; j++) { - const NMNDiscGateway *item2 = &g_array_index(data->gateways, NMNDiscGateway, j); + const NMNDiscGateway *item2 = &nm_g_array_index(data->gateways, NMNDiscGateway, j); nm_assert(!IN6_ARE_ADDR_EQUAL(&item->address, &item2->address)); } @@ -344,12 +350,47 @@ _ASSERT_data_gateways(const NMNDiscDataInternal *data) } /*****************************************************************************/ +static bool +is_duplicate_route(const NMNDiscRoute *r0, const NMNDiscRoute *r1) +{ + return IN6_ARE_ADDR_EQUAL(&r0->network, &r1->network) && r0->plen == r1->plen; +} + +static void +_data_complete_prepare_routes(GArray *routes) +{ + guint i, j; + + for (i = 0; i < routes->len; i++) { + NMNDiscRoute *r0 = &nm_g_array_index(routes, NMNDiscRoute, i); + + r0->duplicate = FALSE; + } + for (i = 0; i < routes->len; i++) { + NMNDiscRoute *r0 = &nm_g_array_index(routes, NMNDiscRoute, i); + + for (j = i + 1; j < routes->len; j++) { + NMNDiscRoute *r1 = &nm_g_array_index(routes, NMNDiscRoute, j); + + if (!is_duplicate_route(r0, r1)) + continue; + + r0->duplicate = TRUE; + r1->duplicate = TRUE; + + /* Maybe after index j, there is yet another duplicate. But we + * will find that later, when i becomes j. */ + break; + } + } +} static const NMNDiscData * _data_complete(NMNDiscDataInternal *data) { _ASSERT_data_gateways(data); + _data_complete_prepare_routes(data->routes); #define _SET(data, field) \ G_STMT_START \ { \ @@ -402,7 +443,7 @@ nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gint64 now_ guint insert_idx = G_MAXUINT; for (i = 0; i < rdata->gateways->len;) { - NMNDiscGateway *item = &g_array_index(rdata->gateways, NMNDiscGateway, i); + NMNDiscGateway *item = &nm_g_array_index(rdata->gateways, NMNDiscGateway, i); if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) { if (new_item->expiry_msec <= now_msec) { @@ -476,12 +517,12 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr) priv->config.network_id, addr->dad_counter++, &error)) { - _LOGW("complete-address: failed to generate an stable-privacy address: %s", + _LOGW("complete-address: failed to generate a stable-privacy address: %s", error->message); g_clear_error(&error); return FALSE; } - _LOGD("complete-address: using an stable-privacy address"); + _LOGD("complete-address: using a stable-privacy address"); return TRUE; } @@ -496,7 +537,7 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr) return TRUE; } - _LOGW("complete-address: can't generate a new_item EUI-64 address"); + _LOGW("complete-address: can't generate a new EUI-64 address"); return FALSE; } @@ -519,7 +560,7 @@ nm_ndisc_add_address(NMNDisc *ndisc, nm_assert((!!from_ra) == (now_msec > 0)); for (i = 0; i < rdata->addresses->len; i++) { - NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, i); + NMNDiscAddress *item = &nm_g_array_index(rdata->addresses, NMNDiscAddress, i); if (from_ra) { /* RFC4862 5.5.3.d, we find an existing address with the same prefix. @@ -651,10 +692,19 @@ nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec rdata = &priv->rdata; for (i = 0; i < rdata->routes->len;) { - NMNDiscRoute *item = &g_array_index(rdata->routes, NMNDiscRoute, i); - - if (IN6_ARE_ADDR_EQUAL(&item->network, &new_item->network) - && item->plen == new_item->plen) { + NMNDiscRoute *item = &nm_g_array_index(rdata->routes, NMNDiscRoute, i); + + /* + * It is possible that two entries in rdata->routes have + * the same prefix as well as the same prefix length. + * One of them, however, refers to the on-link prefix, + * and the other one to a route from the route information field. + * Moreover, they might have different route preferences. + * Hence, if both routes differ in the on-link flag, + * comparison is aborted, and both routes are added. + */ + if (IN6_ARE_ADDR_EQUAL(&item->network, &new_item->network) && item->plen == new_item->plen + && item->on_link == new_item->on_link) { if (new_item->expiry_msec <= now_msec) { g_array_remove_index(rdata->routes, i); return TRUE; @@ -707,7 +757,7 @@ nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 rdata = &priv->rdata; for (i = 0; i < rdata->dns_servers->len; i++) { - NMNDiscDNSServer *item = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); + NMNDiscDNSServer *item = &nm_g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); if (IN6_ARE_ADDR_EQUAL(&item->address, &new_item->address)) { if (new_item->expiry_msec <= now_msec) { @@ -746,7 +796,7 @@ nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 rdata = &priv->rdata; for (i = 0; i < rdata->dns_domains->len; i++) { - item = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); + item = &nm_g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); if (nm_streq(item->domain, new_item->domain)) { if (new_item->expiry_msec <= now_msec) { @@ -989,14 +1039,13 @@ announce_router_solicited(NMNDisc *ndisc) void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) { - gboolean changed = FALSE; - const struct in6_addr *in6arr; - const char *const *strvarr; - NMDedupMultiIter iter; - const NMPObject *obj; - guint len; - guint i; - gint32 fake_now = NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000; + gboolean changed = FALSE; + const char *const *strvarr; + NMDedupMultiIter iter; + const NMPObject *obj; + guint len; + guint i; + gint32 fake_now = NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000; nm_assert(NM_IS_NDISC(ndisc)); nm_assert(nm_ndisc_get_node_type(ndisc) == NM_NDISC_NODE_TYPE_ROUTER); @@ -1035,15 +1084,19 @@ nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) changed = TRUE; } - in6arr = NULL; - len = 0; + strvarr = NULL; + len = 0; if (l3cd) - in6arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET6, &len); + strvarr = nm_l3_config_data_get_nameservers(l3cd, AF_INET6, &len); for (i = 0; i < len; i++) { + struct in6_addr a; NMNDiscDNSServer n; + if (!nm_utils_dnsname_parse_assert(AF_INET6, strvarr[i], NULL, &a, NULL)) + continue; + n = (NMNDiscDNSServer){ - .address = in6arr[i], + .address = a, .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME), }; @@ -1221,28 +1274,35 @@ nm_ndisc_stop(NMNDisc *ndisc) } NMNDiscConfigMap -nm_ndisc_dad_failed(NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal) +nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_signal) { NMNDiscDataInternal *rdata; guint i; + guint j; gboolean changed = FALSE; + g_return_val_if_fail(addresses, NM_NDISC_CONFIG_NONE); + rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - for (i = 0; i < rdata->addresses->len;) { - NMNDiscAddress *item = &g_array_index(rdata->addresses, NMNDiscAddress, i); + for (i = 0; i < addresses->len; i++) { + const struct in6_addr *addr = &nm_g_array_index(addresses, struct in6_addr, i); - if (IN6_ARE_ADDR_EQUAL(&item->address, address)) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + for (j = 0; j < rdata->addresses->len;) { + NMNDiscAddress *item = &nm_g_array_index(rdata->addresses, NMNDiscAddress, j); - _LOGD("DAD failed for discovered address %s", _nm_utils_inet6_ntop(address, sbuf)); - changed = TRUE; - if (!complete_address(ndisc, item)) { - g_array_remove_index(rdata->addresses, i); - continue; + if (IN6_ARE_ADDR_EQUAL(&item->address, addr)) { + char sbuf[NM_INET_ADDRSTRLEN]; + + _LOGI("DAD failed for discovered address %s", nm_inet6_ntop(addr, sbuf)); + changed = TRUE; + if (!complete_address(ndisc, item)) { + g_array_remove_index(rdata->addresses, j); + continue; + } } + j++; } - i++; } if (emit_changed_signal && changed) @@ -1278,7 +1338,7 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed) NMNDiscDataInternal *rdata; guint i; char changedstr[CONFIG_MAP_MAX_STR]; - char addrstr[NM_UTILS_INET_ADDRSTRLEN]; + char addrstr[NM_INET_ADDRSTRLEN]; char str_pref[35]; char str_exp[100]; gint64 now_msec; @@ -1303,42 +1363,42 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed) _LOGD(" retrans timer : %u", (guint) rdata->public.retrans_timer_ms); for (i = 0; i < rdata->gateways->len; i++) { - const NMNDiscGateway *gateway = &g_array_index(rdata->gateways, NMNDiscGateway, i); + const NMNDiscGateway *gateway = &nm_g_array_index(rdata->gateways, NMNDiscGateway, i); _LOGD(" gateway %s pref %s exp %s", - _nm_utils_inet6_ntop(&gateway->address, addrstr), + nm_inet6_ntop(&gateway->address, addrstr), nm_icmpv6_router_pref_to_string(gateway->preference, str_pref, sizeof(str_pref)), get_exp(str_exp, now_msec, gateway)); } for (i = 0; i < rdata->addresses->len; i++) { - const NMNDiscAddress *address = &g_array_index(rdata->addresses, NMNDiscAddress, i); + const NMNDiscAddress *address = &nm_g_array_index(rdata->addresses, NMNDiscAddress, i); _LOGD(" address %s exp %s", - _nm_utils_inet6_ntop(&address->address, addrstr), + nm_inet6_ntop(&address->address, addrstr), get_exp(str_exp, now_msec, address)); } for (i = 0; i < rdata->routes->len; i++) { - const NMNDiscRoute *route = &g_array_index(rdata->routes, NMNDiscRoute, i); - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + const NMNDiscRoute *route = &nm_g_array_index(rdata->routes, NMNDiscRoute, i); + char sbuf[NM_INET_ADDRSTRLEN]; _LOGD(" route %s/%u via %s pref %s exp %s", - _nm_utils_inet6_ntop(&route->network, addrstr), + nm_inet6_ntop(&route->network, addrstr), (guint) route->plen, - _nm_utils_inet6_ntop(&route->gateway, sbuf), + nm_inet6_ntop(&route->gateway, sbuf), nm_icmpv6_router_pref_to_string(route->preference, str_pref, sizeof(str_pref)), get_exp(str_exp, now_msec, route)); } for (i = 0; i < rdata->dns_servers->len; i++) { const NMNDiscDNSServer *dns_server = - &g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); + &nm_g_array_index(rdata->dns_servers, NMNDiscDNSServer, i); _LOGD(" dns_server %s exp %s", - _nm_utils_inet6_ntop(&dns_server->address, addrstr), + nm_inet6_ntop(&dns_server->address, addrstr), get_exp(str_exp, now_msec, dns_server)); } for (i = 0; i < rdata->dns_domains->len; i++) { const NMNDiscDNSDomain *dns_domain = - &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); + &nm_g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i); _LOGD(" dns_domain %s exp %s", dns_domain->domain, get_exp(str_exp, now_msec, dns_domain)); } @@ -1370,7 +1430,7 @@ clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint6 if (rdata->gateways->len == 0) return; - arr = &g_array_index(rdata->gateways, NMNDiscGateway, 0); + arr = &nm_g_array_first(rdata->gateways, NMNDiscGateway); for (i = 0, j = 0; i < rdata->gateways->len; i++) { if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)) @@ -1403,7 +1463,7 @@ clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint if (rdata->addresses->len == 0) return; - arr = &g_array_index(rdata->addresses, NMNDiscAddress, 0); + arr = &nm_g_array_first(rdata->addresses, NMNDiscAddress); for (i = 0, j = 0; i < rdata->addresses->len; i++) { if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)) @@ -1433,7 +1493,7 @@ clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 if (rdata->routes->len == 0) return; - arr = &g_array_index(rdata->routes, NMNDiscRoute, 0); + arr = &nm_g_array_first(rdata->routes, NMNDiscRoute); for (i = 0, j = 0; i < rdata->routes->len; i++) { if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)) @@ -1463,7 +1523,7 @@ clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi if (rdata->dns_servers->len == 0) return; - arr = &g_array_index(rdata->dns_servers, NMNDiscDNSServer, 0); + arr = &nm_g_array_first(rdata->dns_servers, NMNDiscDNSServer); for (i = 0, j = 0; i < rdata->dns_servers->len; i++) { if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)) @@ -1493,7 +1553,7 @@ clean_dns_domains(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gi if (rdata->dns_domains->len == 0) return; - arr = &g_array_index(rdata->dns_domains, NMNDiscDNSDomain, 0); + arr = &nm_g_array_first(rdata->dns_domains, NMNDiscDNSDomain); for (i = 0, j = 0; i < rdata->dns_domains->len; i++) { if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)) @@ -1602,34 +1662,35 @@ calc_pre_expiry_rs_msec(NMNDisc *ndisc) _calc_pre_expiry_rs_msec_worker( &expiry_msec, priv->last_rs_msec, - g_array_index(rdata->gateways, NMNDiscGateway, i).expiry_msec); + nm_g_array_index(rdata->gateways, NMNDiscGateway, i).expiry_msec); } for (i = 0; i < rdata->addresses->len; i++) { _calc_pre_expiry_rs_msec_worker( &expiry_msec, priv->last_rs_msec, - g_array_index(rdata->addresses, NMNDiscAddress, i).expiry_msec); + nm_g_array_index(rdata->addresses, NMNDiscAddress, i).expiry_msec); } for (i = 0; i < rdata->routes->len; i++) { - _calc_pre_expiry_rs_msec_worker(&expiry_msec, - priv->last_rs_msec, - g_array_index(rdata->routes, NMNDiscRoute, i).expiry_msec); + _calc_pre_expiry_rs_msec_worker( + &expiry_msec, + priv->last_rs_msec, + nm_g_array_index(rdata->routes, NMNDiscRoute, i).expiry_msec); } for (i = 0; i < rdata->dns_servers->len; i++) { _calc_pre_expiry_rs_msec_worker( &expiry_msec, priv->last_rs_msec, - g_array_index(rdata->dns_servers, NMNDiscDNSServer, i).expiry_msec); + nm_g_array_index(rdata->dns_servers, NMNDiscDNSServer, i).expiry_msec); } for (i = 0; i < rdata->dns_domains->len; i++) { _calc_pre_expiry_rs_msec_worker( &expiry_msec, priv->last_rs_msec, - g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i).expiry_msec); + nm_g_array_index(rdata->dns_domains, NMNDiscDNSDomain, i).expiry_msec); } return expiry_msec - solicit_retransmit_time_jitter(NM_NDISC_PRE_EXPIRY_TIME_MSEC); diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h index 079ec037..8f1a12a2 100644 --- a/src/core/ndisc/nm-ndisc.h +++ b/src/core/ndisc/nm-ndisc.h @@ -8,7 +8,7 @@ #include <stdlib.h> #include <netinet/in.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include "nm-setting-ip6-config.h" #include "NetworkManagerUtils.h" @@ -20,7 +20,7 @@ #define NM_RA_TIMEOUT_INFINITY ((guint32) G_MAXINT32) #define NM_TYPE_NDISC (nm_ndisc_get_type()) -#define NM_NDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NDISC, NMNDisc)) +#define NM_NDISC(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NDISC, NMNDisc)) #define NM_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_NDISC, NMNDiscClass)) #define NM_IS_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_NDISC)) #define NM_IS_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_NDISC)) @@ -115,6 +115,8 @@ typedef struct _NMNDiscRoute { gint64 expiry_msec; NMIcmpv6RouterPref preference; guint8 plen; + bool on_link : 1; + bool duplicate : 1; } NMNDiscRoute; typedef struct { @@ -228,9 +230,9 @@ NMNDiscNodeType nm_ndisc_get_node_type(NMNDisc *self); gboolean nm_ndisc_set_iid(NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid, gboolean is_token); void nm_ndisc_start(NMNDisc *ndisc); void nm_ndisc_stop(NMNDisc *ndisc); +void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd); NMNDiscConfigMap -nm_ndisc_dad_failed(NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal); -void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd); +nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_signal); NMPlatform *nm_ndisc_get_platform(NMNDisc *self); NMPNetns *nm_ndisc_netns_get(NMNDisc *self); diff --git a/src/core/nm-act-request.h b/src/core/nm-act-request.h index 9075d5b7..4c85735f 100644 --- a/src/core/nm-act-request.h +++ b/src/core/nm-act-request.h @@ -10,7 +10,8 @@ #include "nm-active-connection.h" #define NM_TYPE_ACT_REQUEST (nm_act_request_get_type()) -#define NM_ACT_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ACT_REQUEST, NMActRequest)) +#define NM_ACT_REQUEST(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ACT_REQUEST, NMActRequest)) #define NM_ACT_REQUEST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_ACT_REQUEST, NMActRequestClass)) #define NM_IS_ACT_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_ACT_REQUEST)) diff --git a/src/core/nm-active-connection.c b/src/core/nm-active-connection.c index 49568f7c..6f62a601 100644 --- a/src/core/nm-active-connection.c +++ b/src/core/nm-active-connection.c @@ -81,6 +81,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMActiveConnection, PROP_DHCP6_CONFIG, PROP_VPN, PROP_MASTER, + PROP_CONTROLLER, PROP_INT_SETTINGS_CONNECTION, PROP_INT_APPLIED_CONNECTION, @@ -116,22 +117,22 @@ static void auth_complete(NMActiveConnection *self, gboolean result, const char #define _NMLOG_DOMAIN LOGD_DEVICE #define _NMLOG_PREFIX_NAME "active-connection" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _sbuf[64]; \ - NMActiveConnectionPrivate *_priv = self ? NM_ACTIVE_CONNECTION_GET_PRIVATE(self) : NULL; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - (_priv && _priv->device) ? nm_device_get_iface(_priv->device) : NULL, \ - (_priv && _priv->applied_connection) \ - ? nm_connection_get_uuid(_priv->applied_connection) \ - : NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf(_sbuf, "[%p]", self) : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + char _sbuf[64]; \ + NMActiveConnectionPrivate *_priv = self ? NM_ACTIVE_CONNECTION_GET_PRIVATE(self) : NULL; \ + \ + nm_log((level), \ + _NMLOG_DOMAIN, \ + (_priv && _priv->device) ? nm_device_get_iface(_priv->device) : NULL, \ + (_priv && _priv->applied_connection) \ + ? nm_connection_get_uuid(_priv->applied_connection) \ + : NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR_STR(self, _sbuf) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ G_STMT_END /*****************************************************************************/ @@ -803,7 +804,7 @@ check_master_ready(NMActiveConnection *self) * ensure that if the master connection was created without a device * that we notify clients when the master device is known. */ - _notify(self, PROP_MASTER); + nm_gobject_notify_together(self, PROP_MASTER, PROP_CONTROLLER); } } @@ -1343,6 +1344,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_VPN: g_value_set_boolean(value, priv->vpn); break; + case PROP_CONTROLLER: case PROP_MASTER: if (priv->master) master_device = nm_active_connection_get_device(priv->master); @@ -1440,8 +1442,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* construct-only */ priv->vpn = g_value_get_boolean(value); break; - case PROP_MASTER: - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1601,6 +1601,9 @@ static const NMDBusInterfaceInfoExtended interface_info_active_connection = { "o", NM_ACTIVE_CONNECTION_DHCP6_CONFIG), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Vpn", "b", NM_ACTIVE_CONNECTION_VPN), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Controller", + "o", + NM_ACTIVE_CONNECTION_CONTROLLER), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Master", "o", NM_ACTIVE_CONNECTION_MASTER), ), ), @@ -1732,6 +1735,13 @@ nm_active_connection_class_init(NMActiveConnectionClass *ac_class) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CONTROLLER] = + g_param_spec_string(NM_ACTIVE_CONNECTION_CONTROLLER, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /* Internal properties */ obj_properties[PROP_INT_SETTINGS_CONNECTION] = g_param_spec_object(NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, diff --git a/src/core/nm-active-connection.h b/src/core/nm-active-connection.h index 28d4246e..15db68c3 100644 --- a/src/core/nm-active-connection.h +++ b/src/core/nm-active-connection.h @@ -12,7 +12,7 @@ #define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type()) #define NM_ACTIVE_CONNECTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection)) #define NM_ACTIVE_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionClass)) #define NM_IS_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_ACTIVE_CONNECTION)) @@ -38,6 +38,7 @@ #define NM_ACTIVE_CONNECTION_DHCP6_CONFIG "dhcp6-config" #define NM_ACTIVE_CONNECTION_VPN "vpn" #define NM_ACTIVE_CONNECTION_MASTER "master" +#define NM_ACTIVE_CONNECTION_CONTROLLER "controller" /* Internal non-exported properties */ #define NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION "int-settings-connection" diff --git a/src/core/nm-audit-manager.h b/src/core/nm-audit-manager.h index 3a7ea7c0..47ab8b76 100644 --- a/src/core/nm-audit-manager.h +++ b/src/core/nm-audit-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_AUDIT_MANAGER (nm_audit_manager_get_type()) #define NM_AUDIT_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManager)) #define NM_AUDIT_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_AUDIT_MANAGER, NMAuditManagerClass)) #define NM_IS_AUDIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_AUDIT_MANAGER)) diff --git a/src/core/nm-auth-manager.c b/src/core/nm-auth-manager.c index 0f7e0c0d..242f0055 100644 --- a/src/core/nm-auth-manager.c +++ b/src/core/nm-auth-manager.c @@ -524,7 +524,7 @@ _name_owner_get_cb(const char *name_owner, GError *error, gpointer user_data) /*****************************************************************************/ NMAuthManager * -nm_auth_manager_get() +nm_auth_manager_get(void) { g_return_val_if_fail(singleton_instance, NULL); diff --git a/src/core/nm-auth-manager.h b/src/core/nm-auth-manager.h index db6237d8..4ebad11b 100644 --- a/src/core/nm-auth-manager.h +++ b/src/core/nm-auth-manager.h @@ -40,7 +40,7 @@ nm_auth_call_result_eval(gboolean is_authorized, gboolean is_challenge, GError * #define NM_TYPE_AUTH_MANAGER (nm_auth_manager_get_type()) #define NM_AUTH_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AUTH_MANAGER, NMAuthManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AUTH_MANAGER, NMAuthManager)) #define NM_AUTH_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_AUTH_MANAGER, NMAuthManagerClass)) #define NM_IS_AUTH_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_AUTH_MANAGER)) diff --git a/src/core/nm-bond-manager.c b/src/core/nm-bond-manager.c new file mode 100644 index 00000000..2d15b0b5 --- /dev/null +++ b/src/core/nm-bond-manager.c @@ -0,0 +1,967 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-bond-manager.h" + +#include <linux/if.h> + +#include "NetworkManagerUtils.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" +#include "nm-firewall-utils.h" + +/*****************************************************************************/ + +typedef enum _nm_packed { + REGISTRATION_STATE_NONE, + REGISTRATION_STATE_UPPING, + REGISTRATION_STATE_UP, + REGISTRATION_STATE_DOWNING, +} RegistrationState; + +struct _NMBondManager { + NMPlatform *platform; + + NMBondManagerCallback callback; + gpointer user_data; + + /* This is only used for structured logging. */ + char *connection_uuid; + + GSource *reconfigure_on_idle_source; + + /* During _reconfigure_check() we remember all ifindexes that are part + * of the current SLB bond. This is used during _link_changed_cb() to + * figure out whether a change on the interface might be relevant to + * trigger a _reconfigure_check() on idle. */ + GHashTable *previous_ifindexes; + + /* We need to keep track of active members that we configured in NFT. + * That is, because on update we use "add && flush" to reset the table, + * however that leaves empty chains around. If we previously had an active + * member, a chain for it was created that we need to clean up. + * + * Before every NFT call we use this to generate the list of members that + * are to be cleaned up. Thereby also adding the new active-memebers to + * the list. When the NFT calls returns with success, we can prune the + * now deleted member/chain. */ + GHashTable *previous_members; + + GCancellable *cancellable; + + struct { + char *bond_ifname_curr; + char *bond_ifname_next; + const char **active_members_curr; + const char **active_members_next; + } dat; + + gulong link_changed_id; + int ifindex; + RegistrationState reg_state; + bool destroyed : 1; + + /* Whether we noticed some changes that require us to _reconfigure_check(). + * Note that while a NFT call is pending, we postpone the check. */ + bool reconfigure_check : 1; + + /* Whether a `nft` call is in progress. Usually this corresponds to + * having a cancellable, however, we may also cancel and clear the + * cancellable while the call is still in progress. */ + bool nft_in_progress : 1; + + /* Whether the last NFT invocation was good. If not, we may have + * an invalid state. Actually unused, so far because it's not + * clear what to do about failure to configure NFT (aside logging + * a warning). */ + bool nft_good : 1; + + /* The overall state. DEFAULT means that an update is pending. + * FALSE means that the last "nft" command failed. + * TRUE means that the last "nft" command was good. */ + NMOptionBool state : 3; +}; + +#define NM_IS_BOND_MANAGER(self) \ + ({ \ + const NMBondManager *_self = (self); \ + \ + (_self && NM_IS_PLATFORM(_self->platform)); \ + }) + +/*****************************************************************************/ + +static void _nft_call(NMBondManager *self, + gboolean up, + const char *bond_ifname, + const char *const *bond_ifnames_down, + const char *const *active_members); + +static void _bond_manager_destroy(NMBondManager *self); + +static void _reconfigure_check(NMBondManager *self, gboolean reapply); + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_DEVICE +#define _NMLOG_PREFIX_NAME "mlag" +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel _level = (level); \ + \ + if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ + NMBondManager *const _self = (self); \ + const char *_ifname = nm_platform_link_get_name(_self->platform, _self->ifindex); \ + char _sbuf[30]; \ + \ + _nm_log(_level, \ + _NMLOG_DOMAIN, \ + 0, \ + _ifname, \ + _self->connection_uuid, \ + "%s[" NM_HASH_OBFUSCATE_PTR_FMT ", %s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR(_self), \ + (_ifname ?: nm_sprintf_buf(_sbuf, "(%d)", _self->ifindex)) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +static const char * +_log_info(NMStrBuf *strbuf, + const char *bond_ifname, + const char *const *active_members, + const char *const *previous_members) +{ + gsize i; + + nm_str_buf_reset(strbuf); + + if (!bond_ifname) + nm_str_buf_append(strbuf, "(disabled)"); + else { + nm_str_buf_append_printf(strbuf, "(enabled, \"%s\"", bond_ifname); + + for (i = 0; active_members && active_members[i]; i++) { + if (i == 0) + nm_str_buf_append(strbuf, ", active-members=[ \""); + else + nm_str_buf_append(strbuf, "\", \""); + nm_str_buf_append(strbuf, active_members[i]); + } + if (i > 0) + nm_str_buf_append(strbuf, "\" ]"); + + for (i = 0; previous_members && previous_members[i]; i++) { + nm_assert(!nm_strv_contains(active_members, -1, previous_members[i])); + if (i == 0) + nm_str_buf_append(strbuf, ", previous-members=[ \""); + else + nm_str_buf_append(strbuf, "\", \""); + nm_str_buf_append(strbuf, previous_members[i]); + } + if (i > 0) + nm_str_buf_append(strbuf, "\" ]"); + + nm_str_buf_append(strbuf, ")"); + } + + return nm_str_buf_get_str(strbuf); +} + +/*****************************************************************************/ + +static gboolean +_nm_assert_self_(NMBondManager *self) +{ + nm_assert(self); + nm_assert(NM_IS_PLATFORM(self->platform)); + nm_assert(!self->cancellable || G_IS_CANCELLABLE(self->cancellable)); + nm_assert(!self->cancellable || !g_cancellable_is_cancelled(self->cancellable)); + nm_assert(!self->dat.active_members_curr || self->dat.bond_ifname_curr); + nm_assert(!self->dat.active_members_next || self->dat.bond_ifname_next); + nm_assert(!self->cancellable || self->nft_in_progress); + nm_assert(!self->reconfigure_on_idle_source || self->reconfigure_check); + nm_assert(!self->nft_in_progress || !self->reconfigure_on_idle_source); + + nm_assert(!self->dat.active_members_curr || self->dat.bond_ifname_curr[0]); + nm_assert(!self->dat.active_members_next || self->dat.bond_ifname_next[0]); + + nm_assert(!self->destroyed || !self->dat.bond_ifname_next); + nm_assert(!self->destroyed + || NM_IN_SET((RegistrationState) self->reg_state, + REGISTRATION_STATE_UPPING, + REGISTRATION_STATE_DOWNING)); + + switch (self->reg_state) { + case REGISTRATION_STATE_NONE: + nm_assert(!self->nft_in_progress); + nm_assert(!self->cancellable); + nm_assert(!self->dat.bond_ifname_curr); + nm_assert(!self->dat.bond_ifname_next); + break; + case REGISTRATION_STATE_UPPING: + nm_assert(self->nft_in_progress); + nm_assert(self->dat.bond_ifname_curr); + break; + case REGISTRATION_STATE_UP: + nm_assert(!self->nft_in_progress); + nm_assert(!self->cancellable); + nm_assert(self->dat.bond_ifname_curr); + nm_assert(!self->dat.bond_ifname_next); + break; + case REGISTRATION_STATE_DOWNING: + nm_assert(self->nft_in_progress); + nm_assert(self->dat.bond_ifname_curr); + break; + default: + nm_assert_not_reached(); + break; + } + + return TRUE; +} + +#define _nm_assert_self(self) nm_assert(_nm_assert_self_(self)) + +/*****************************************************************************/ + +static void +_callback_invoke(NMBondManager *self, NMBondManagerEventType event_type) +{ + if (!self->callback) + return; + + self->callback(self, event_type, self->user_data); +} + +static void +_notify_state_change(NMBondManager *self) +{ + NMOptionBool state; + + if (self->nft_in_progress) + state = NM_OPTION_BOOL_DEFAULT; + else + state = !!self->nft_good; + + if (state == self->state) + return; + + self->state = state; + _callback_invoke(self, NM_BOND_MANAGER_EVENT_TYPE_STATE); +} + +/*****************************************************************************/ + +static void +_nft_call_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); + NMBondManager *self; + gpointer ptr_up; + gs_free const char **previous_members = NULL; + gs_free_error GError *error = NULL; + + nm_utils_user_data_unpack(user_data, &self, &ptr_up, &previous_members); + + _nm_assert_self(self); + + self->nft_in_progress = FALSE; + + nm_firewall_nft_call_finish(result, &error); + + if (!error) { + gsize i; + + /* On success, we can forget about our previous members that we successfully + * deleted. */ + if (!GPOINTER_TO_INT(ptr_up)) { + /* We successfully deleted the NFT table. Forget all previous members. */ + g_hash_table_remove_all(self->previous_members); + } else if (previous_members) { + /* These previous members are now forgotten for good. */ + for (i = 0; previous_members[i]; i++) + g_hash_table_remove(self->previous_members, previous_members[i]); + } + } else { + /* If all our NFT calls keep failing, we never actually prune entries from + * self->previous_members. That is a problem, however, under normal operation + * NFT calls should not continuously fail, and we would have a small fixed + * number of active-members. */ + } + + nm_clear_g_cancellable(&self->cancellable); + + if (nm_utils_error_is_cancelled(error)) { + switch (self->reg_state) { + case REGISTRATION_STATE_NONE: + case REGISTRATION_STATE_UP: + case REGISTRATION_STATE_DOWNING: + /* It is not expected that we cancel anything in this state. */ + nm_assert_not_reached(); + goto out; + case REGISTRATION_STATE_UPPING: + nm_assert(self->dat.bond_ifname_curr); + /* We cancelled while upping. We need to issue another down, + * to make sure the data is gone. */ + if (!self->dat.bond_ifname_next) { + /* There is no other name to configure. We just need to down + * the current one. */ + _LOGT("reconfigure: configuration cancelled, deconfigure %s", + self->dat.bond_ifname_curr); + _nft_call(self, FALSE, self->dat.bond_ifname_curr, NULL, NULL); + self->reg_state = REGISTRATION_STATE_DOWNING; + goto out; + } + /* There is already another configuration. UPPING again. */ + _LOGT("reconfigure: configuration cancelled, configure %s", + _log_info(&strbuf, + self->dat.bond_ifname_next, + self->dat.active_members_next, + NULL)); + _nft_call(self, + TRUE, + self->dat.bond_ifname_next, + NM_MAKE_STRV(self->dat.bond_ifname_curr), + self->dat.active_members_next); + self->reg_state = REGISTRATION_STATE_UPPING; + nm_clear_g_free(&self->dat.bond_ifname_curr); + nm_clear_g_free(&self->dat.active_members_curr); + self->dat.bond_ifname_curr = g_steal_pointer(&self->dat.bond_ifname_next); + self->dat.active_members_curr = g_steal_pointer(&self->dat.active_members_next); + goto out; + } + nm_assert_not_reached(); + goto out; + } + + if (error) { + self->nft_good = FALSE; + } else { + /* Technically, if a previous downing failed, we cannot know that + * we were able to fix this bug a successful run now. That is, because + * if the interface got renamed, and the downing for the previous + * interface name failed, we leak that table and the success now doesn't + * fix that. + * + * That is a bug, but probably not severe because: + * - interfaces are not supposed to be renamed. + * - if this NFT command succeed, we expect that also the previous downings worked. + * + * The problem here is only that nft_good might lie and indicate + * no problem. However, when a downing fails, we anyway leak the table already + * and the bad thing happend. We cannot fix if `nft` command fails. + */ + self->nft_good = TRUE; + } + + switch (self->reg_state) { + case REGISTRATION_STATE_NONE: + case REGISTRATION_STATE_UP: + /* Unexpected to get a callback completion in these states. */ + nm_assert_not_reached(); + goto out; + case REGISTRATION_STATE_UPPING: + nm_assert(!self->dat.bond_ifname_next); + if (error) { + /* Unclear what to do about this error. Just log about it, nothing else. */ + _LOGW("reconfigure: nft configuration for balance-slb failed: %s", error->message); + } else + _LOGT("reconfigure: configuration completed"); + self->reg_state = REGISTRATION_STATE_UP; + goto out; + case REGISTRATION_STATE_DOWNING: + nm_assert(self->dat.bond_ifname_curr); + if (!self->dat.bond_ifname_next) { + if (error) { + /* Unclear what to do about this error. Just log about it, nothing else. */ + _LOGW("reconfigure: nft deconfiguration for balance-slb failed: %s", + error->message); + } else + _LOGT("reconfigure: deconfiguration completed"); + nm_clear_g_free(&self->dat.bond_ifname_curr); + nm_clear_g_free(&self->dat.active_members_curr); + self->reg_state = REGISTRATION_STATE_NONE; + + if (self->destroyed) { + _bond_manager_destroy(self); + return; + } + + goto out; + } + if (error) { + /* Unclear what to do about this error. Just log about it, nothing else. */ + _LOGW("reconfigure: nft deconfiguration failed before restart: %s", error->message); + } else + _LOGT("reconfigure: deconfiguration completed before restart"); + _nft_call(self, + TRUE, + self->dat.bond_ifname_next, + NM_MAKE_STRV(self->dat.bond_ifname_curr), + self->dat.active_members_next); + nm_clear_g_free(&self->dat.bond_ifname_curr); + nm_clear_g_free(&self->dat.active_members_curr); + self->dat.bond_ifname_curr = g_steal_pointer(&self->dat.bond_ifname_next); + self->dat.active_members_curr = g_steal_pointer(&self->dat.active_members_next); + self->reg_state = REGISTRATION_STATE_UPPING; + goto out; + } + + nm_assert_not_reached(); + +out: + if (self->reconfigure_check) { + if (self->destroyed) + nm_assert_not_reached(); + else if (!self->nft_in_progress) { + nm_assert(!self->reconfigure_on_idle_source); + _reconfigure_check(self, FALSE); + } + } + + _notify_state_change(self); +} + +static void +_nft_call(NMBondManager *self, + gboolean up, + const char *bond_ifname, + const char *const *bond_ifnames_down, + const char *const *active_members) +{ + gs_unref_bytes GBytes *stdin_buf = NULL; + gs_free const char *const *previous_members_strv = NULL; + + if (up) { + gs_unref_ptrarray GPtrArray *arr = NULL; + GHashTableIter iter; + const char *n; + gsize i; + + /* We need to track the active-members that we add, because, when we update the + * NFT table without the member from previously, we use "add && flush", which + * leaves empty chains for the previous members around. We need to cleanup those + * chains, hence the need to track which members we ever added. + * + * Before making an UP call, we add the newly configured active_members to the list + * of previous_members. All the while, passing a list of previous_members_strv + * which we currently no longer configure. + * + * Only when the call succeeds (in _nft_call_cb()), we will forget about previously added + * members. This is done by passing the list of members that we are forgetting now + * on to the callback below. */ + + /* Get the list of previous members that are no longer in the current + * active list. */ + g_hash_table_iter_init(&iter, self->previous_members); + while (g_hash_table_iter_next(&iter, (gpointer *) &n, NULL)) { + if (nm_strv_contains(active_members, -1, n)) + continue; + if (!arr) + arr = g_ptr_array_new(); + g_ptr_array_add(arr, (gpointer) n); + } + if (arr) { + nm_strv_sort((const char **) arr->pdata, arr->len); + previous_members_strv = nm_strv_dup_packed((const char *const *) arr->pdata, arr->len); + } + + /* The now active member also get tracked as previous members for the future. */ + if (active_members) { + for (i = 0; active_members[i]; i++) + g_hash_table_add(self->previous_members, g_strdup(active_members[i])); + } + } + + stdin_buf = nm_firewall_nft_stdio_mlag(up, + bond_ifname, + bond_ifnames_down, + active_members, + previous_members_strv); + + nm_clear_g_cancellable(&self->cancellable); + self->cancellable = g_cancellable_new(); + + nm_shutdown_wait_obj_register_cancellable(self->cancellable, "nft-mlag"); + + if (_LOGT_ENABLED()) { + if (up) { + nm_auto_str_buf NMStrBuf strbuf = + NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); + + _LOGT("reconfigure: call nft: %s", + _log_info(&strbuf, bond_ifname, active_members, previous_members_strv)); + } else + _LOGT("reconfigure: call nft: disable on \"%s\"", bond_ifname); + } + + self->nft_in_progress = TRUE; + + if (self->reconfigure_check) + nm_clear_g_source_inst(&self->reconfigure_on_idle_source); + + nm_firewall_nft_call(stdin_buf, + self->cancellable, + _nft_call_cb, + nm_utils_user_data_pack(self, + GINT_TO_POINTER(up), + g_steal_pointer(&previous_members_strv))); +} + +/*****************************************************************************/ + +static void +_reconfigure_do(NMBondManager *self, + gboolean reapply, + const char *bond_ifname, + const char **active_members_take) +{ + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); + gs_free const char **active_members = g_steal_pointer(&active_members_take); + + _nm_assert_self(self); + nm_assert(!active_members || bond_ifname); + nm_assert(!active_members || active_members[0]); + + /* The difficulty of all of this is "state". In particular, since we make the nft call + * async, we need to handle all the possible cases, how an update event can invalidate + * a currently pending call. */ + + switch (self->reg_state) { + case REGISTRATION_STATE_NONE: + nm_assert(!self->dat.bond_ifname_curr); + nm_assert(!self->dat.active_members_curr); + nm_assert(!self->dat.bond_ifname_next); + nm_assert(!self->dat.active_members_next); + nm_assert(!self->cancellable); + nm_assert(!self->nft_in_progress); + + if (!bond_ifname) { + /* No configuration done. Nothing to do. */ + goto out; + } + + _LOGT("reconfigure: start configuring (%s)", + _log_info(&strbuf, bond_ifname, active_members, NULL)); + self->dat.bond_ifname_curr = g_strdup(bond_ifname); + self->dat.active_members_curr = nm_strv_dup_packed(active_members, -1); + _nft_call(self, TRUE, self->dat.bond_ifname_curr, NULL, self->dat.active_members_curr); + self->reg_state = REGISTRATION_STATE_UPPING; + goto out; + case REGISTRATION_STATE_UPPING: + nm_assert(self->dat.bond_ifname_curr); + nm_assert(self->nft_in_progress); + + /* We are UPPING, we cancel the pending operation and will + * handle the rest when the callback completes. */ + if (!bond_ifname) { + if (self->cancellable || self->dat.bond_ifname_next) + _LOGT("reconfigure: aborting configuring"); + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + nm_clear_g_cancellable(&self->cancellable); + goto out; + } + if (!reapply && self->cancellable && nm_streq0(bond_ifname, self->dat.bond_ifname_curr) + && nm_strv_equal(active_members, self->dat.active_members_curr)) { + /* Nothing to do. We are already upping this setup. */ + nm_assert(!self->dat.bond_ifname_next); + nm_assert(!self->dat.active_members_next); + goto out; + } + if (!reapply && !self->cancellable && nm_streq0(bond_ifname, self->dat.bond_ifname_next) + && nm_strv_equal(active_members, self->dat.active_members_next)) { + /* We already cancelled the current upping, and have scheduled another + * (identical) run. Nothing to do. */ + goto out; + } + _LOGT("reconfigure: abort configuring to configure %s", + _log_info(&strbuf, bond_ifname, active_members, NULL)); + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + self->dat.bond_ifname_next = g_strdup(bond_ifname); + self->dat.active_members_next = nm_strv_dup_packed(active_members, -1); + nm_clear_g_cancellable(&self->cancellable); + goto out; + case REGISTRATION_STATE_UP: + nm_assert(self->dat.bond_ifname_curr); + nm_assert(!self->dat.bond_ifname_next); + nm_assert(!self->dat.active_members_next); + nm_assert(!self->cancellable); + nm_assert(!self->nft_in_progress); + + if (!bond_ifname) { + _LOGT("reconfigure: deconfigure to disable"); + _nft_call(self, FALSE, self->dat.bond_ifname_curr, NULL, NULL); + self->reg_state = REGISTRATION_STATE_DOWNING; + goto out; + } + if (!reapply && nm_streq0(bond_ifname, self->dat.bond_ifname_curr) + && nm_strv_equal(active_members, self->dat.active_members_curr)) { + /* Nothing to do. The current configuration is already active. */ + goto out; + } + _LOGT("reconfigure: configure, update to %s", + _log_info(&strbuf, bond_ifname, active_members, NULL)); + _nft_call(self, + TRUE, + bond_ifname, + NM_MAKE_STRV(self->dat.bond_ifname_curr), + active_members); + self->reg_state = REGISTRATION_STATE_UPPING; + nm_clear_g_free(&self->dat.bond_ifname_curr); + nm_clear_g_free(&self->dat.active_members_curr); + self->dat.bond_ifname_curr = g_strdup(bond_ifname); + self->dat.active_members_curr = nm_strv_dup_packed(active_members, -1); + goto out; + case REGISTRATION_STATE_DOWNING: + nm_assert(self->dat.bond_ifname_curr); + nm_assert(self->nft_in_progress); + + /* we are already DOWNING. It suffices to clear the scheduled "next" + * config and wait, and reset the "next" configuration. */ + if (nm_streq0(bond_ifname, self->dat.bond_ifname_next) + && nm_strv_equal(active_members, self->dat.active_members_next)) { + /* Nothing to do. */ + goto out; + } + _LOGT("reconfigure: deconfiguring and waiting for %s", + _log_info(&strbuf, bond_ifname, active_members, NULL)); + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + if (bond_ifname) { + self->dat.bond_ifname_next = g_strdup(bond_ifname); + self->dat.active_members_next = nm_strv_dup_packed(active_members, -1); + } + goto out; + } + nm_assert_not_reached(); + +out: + _notify_state_change(self); +} + +static void +_reconfigure_check(NMBondManager *self, gboolean reapply) +{ + const NMPlatformLink *plink_ctrl; + const NMPlatformLink *plink_port; + const NMPlatformLnkBond *plnkbond_ctrl; + NMDedupMultiIter pliter; + const NMDedupMultiHeadEntry *pl_links_head_entry; + const char *active_members_lst_stack[16]; + gs_free const char **active_members_lst_heap = NULL; + const char **active_members_lst = active_members_lst_stack; + gsize active_members_alloc = G_N_ELEMENTS(active_members_lst_stack); + gsize active_members_n = 0; + gs_free const char **active_members_result = NULL; + const char *bond_ifname = NULL; + + _nm_assert_self(self); + nm_assert(!self->destroyed); + + self->reconfigure_check = FALSE; + nm_clear_g_source_inst(&self->reconfigure_on_idle_source); + + g_hash_table_remove_all(self->previous_ifindexes); + + plnkbond_ctrl = nm_platform_link_get_lnk_bond(self->platform, self->ifindex, &plink_ctrl); + + /* We only do bonding-slb MLAG handling if our ifindex is a bond with + * mode=balance-xor && xmit_hash_policy=vlan+srcmac. */ + if (!plnkbond_ctrl) + goto out; + if (!plink_ctrl) + goto out; + if (plink_ctrl->type != NM_LINK_TYPE_BOND) + goto out; + if (plnkbond_ctrl->mode != NM_BOND_MODE_XOR) + goto out; + if (plnkbond_ctrl->xmit_hash_policy != NM_BOND_XMIT_HASH_POLICY_VLAN_SRCMAC) + goto out; + + /* Find all the connected ports that are IFF_RUNNING. */ + pl_links_head_entry = nm_platform_lookup_obj_type(self->platform, NMP_OBJECT_TYPE_LINK); + nmp_cache_iter_for_each_link (&pliter, pl_links_head_entry, &plink_port) { + if (plink_port->master != self->ifindex) + continue; + if (!NM_FLAGS_HAS(plink_port->n_ifi_flags, IFF_RUNNING)) + continue; + + g_hash_table_add(self->previous_ifindexes, GINT_TO_POINTER(plink_port->ifindex)); + + if (active_members_n == active_members_alloc) { + active_members_alloc *= 2; + active_members_lst_heap = + g_renew(const char *, active_members_lst_heap, active_members_alloc); + if (active_members_lst == active_members_lst_stack) { + memcpy(active_members_lst_heap, + active_members_lst_stack, + sizeof(const char *) * active_members_n); + } + active_members_lst = active_members_lst_heap; + } + + active_members_lst[active_members_n++] = plink_port->name; + } + + if (active_members_n > 0) { + gsize i; + gsize j; + + /* We sort the active members by name */ + g_qsort_with_data(active_members_lst, + active_members_n, + sizeof(const char *), + nm_strcmp_p_with_data, + NULL); + + /* There really shouldn't be any duplicates. Nonetheless, check + * and drop them. They must be unique, because nm_firewall_nft_stdio_mlag() + * relies on that. */ + for (j = 1, i = 1; i < active_members_n; i++) { + if (nm_streq(active_members_lst[j - 1], active_members_lst[i])) { + /* Repeated. Skip. */ + continue; + } + if (j != i) + active_members_lst[j] = active_members_lst[i]; + j++; + } + active_members_n = j; + + active_members_result = g_new(const char *, active_members_n + 1u); + j = 0; + + if (self->dat.active_members_curr) { + /* We configured a list earlier. We want to preserve the sort order + * from before. Prefer entries that we already had, in their previous + * order. */ + for (i = 0; self->dat.active_members_curr[i]; i++) { + gssize idx; + + /* We cannot use binary search, because we steal the elements we found + * already. Hence this is O(n^2). We could use binary search if we would + * not modify active_members_lst, but then we would need to remember + * somehow which elements are already consumed. */ + idx = nm_strv_find_first(active_members_lst, + active_members_n, + self->dat.active_members_curr[i]); + if (idx >= 0) + active_members_result[j++] = g_steal_pointer(&active_members_lst[idx]); + } + } + + /* append the remaining entries, which are sorted by name. */ + for (i = 0; i < active_members_n; i++) { + if (active_members_lst[i]) + active_members_result[j++] = active_members_lst[i]; + } + + nm_assert(j == active_members_n); + active_members_result[j] = NULL; + } + + bond_ifname = plink_ctrl->name; + +out: + _reconfigure_do(self, reapply, bond_ifname, g_steal_pointer(&active_members_result)); +} + +static gboolean +_reconfigure_check_on_idle_cb(gpointer user_data) +{ + NMBondManager *self = user_data; + + nm_assert(!self->nft_in_progress); + _reconfigure_check(self, FALSE); + return G_SOURCE_CONTINUE; +} + +/*****************************************************************************/ + +static void +_link_changed_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + const NMPlatformLink *plink, + int change_type_i, + NMBondManager *self) +{ + if (self->reconfigure_check) { + /* Recheck already scheduled. */ + return; + } + + if (self->destroyed) { + /* We should not get another event at this point. Anyway, ignore. */ + return; + } + + if (ifindex == self->ifindex) + goto schedule; + + if (plink->master == self->ifindex) + goto schedule; + + if (g_hash_table_contains(self->previous_ifindexes, GINT_TO_POINTER(ifindex))) + goto schedule; + + /* This event is not relevant. Skip. */ + return; + +schedule: + self->reconfigure_check = TRUE; + if (!self->nft_in_progress) { + self->reconfigure_on_idle_source = + nm_g_idle_add_source(_reconfigure_check_on_idle_cb, self); + } +} + +/*****************************************************************************/ + +void +nm_bond_manager_reapply(NMBondManager *self) +{ + _reconfigure_check(self, TRUE); +} + +/*****************************************************************************/ + +int +nm_bond_manager_get_ifindex(NMBondManager *self) +{ + nm_assert(NM_IS_BOND_MANAGER(self)); + + return self->ifindex; +} + +const char * +nm_bond_manager_get_connection_uuid(NMBondManager *self) +{ + nm_assert(NM_IS_BOND_MANAGER(self)); + + return self->connection_uuid; +} + +NMOptionBool +nm_bond_manager_get_state(NMBondManager *self) +{ + nm_assert(NM_IS_BOND_MANAGER(self)); + + return self->state; +} + +/*****************************************************************************/ + +NMBondManager * +nm_bond_manager_new(struct _NMPlatform *platform, + int ifindex, + const char *connection_uuid, + NMBondManagerCallback callback, + gpointer user_data) +{ + NMBondManager *self; + + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ifindex > 0); + + self = g_slice_new(NMBondManager); + *self = (NMBondManager){ + .platform = g_object_ref(platform), + .ifindex = ifindex, + .reg_state = REGISTRATION_STATE_NONE, + .destroyed = FALSE, + .nft_good = TRUE, + .callback = callback, + .user_data = user_data, + .previous_ifindexes = g_hash_table_new(nm_direct_hash, NULL), + .previous_members = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL), + .connection_uuid = g_strdup(connection_uuid), + .state = NM_OPTION_BOOL_DEFAULT, + }; + + self->link_changed_id = g_signal_connect(self->platform, + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK(_link_changed_cb), + self); + + _LOGT("new balance-slb (MLAG) manager for interface %d", self->ifindex); + + _reconfigure_check(self, TRUE); + + return self; +} + +void +nm_bond_manager_destroy(NMBondManager *self) +{ + g_return_if_fail(self); + g_return_if_fail(!self->destroyed); + + self->destroyed = TRUE; + + self->callback = NULL; + self->user_data = NULL; + + nm_clear_g_signal_handler(self->platform, &self->link_changed_id); + + nm_clear_g_source_inst(&self->reconfigure_on_idle_source); + self->reconfigure_check = FALSE; + + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + + switch (self->reg_state) { + case REGISTRATION_STATE_NONE: + break; + case REGISTRATION_STATE_UPPING: + /* We still have some nfts registered. We need to wrap them up. */ + _LOGT("destroying but deconfigure pending configuration first"); + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + nm_clear_g_cancellable(&self->cancellable); + return; + case REGISTRATION_STATE_UP: + _LOGT("destroying but deconfigure first"); + _nft_call(self, FALSE, self->dat.bond_ifname_curr, NULL, NULL); + self->reg_state = REGISTRATION_STATE_DOWNING; + return; + case REGISTRATION_STATE_DOWNING: + _LOGT("destroying but wait for deconfiguring"); + return; + } + + _bond_manager_destroy(self); +} + +static void +_bond_manager_destroy(NMBondManager *self) +{ + _LOGT("destroyed"); + + nm_assert(self); + nm_assert(self->destroyed); + nm_assert(self->reg_state == REGISTRATION_STATE_NONE); + nm_assert(self->link_changed_id == 0); + nm_assert(!self->cancellable); + nm_assert(!self->dat.bond_ifname_curr); + nm_assert(!self->dat.active_members_curr); + nm_assert(!self->reconfigure_on_idle_source); + + nm_clear_g_free(&self->dat.bond_ifname_next); + nm_clear_g_free(&self->dat.active_members_next); + + g_object_unref(self->platform); + g_hash_table_unref(self->previous_ifindexes); + g_hash_table_unref(self->previous_members); + g_free(self->connection_uuid); + nm_g_slice_free(self); +} diff --git a/src/core/nm-bond-manager.h b/src/core/nm-bond-manager.h new file mode 100644 index 00000000..92a89f0b --- /dev/null +++ b/src/core/nm-bond-manager.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_BOND_MANAGER_H__ +#define __NM_BOND_MANAGER_H__ + +typedef struct _NMBondManager NMBondManager; + +struct _NMPlatform; + +typedef enum { + NM_BOND_MANAGER_EVENT_TYPE_STATE, +} NMBondManagerEventType; + +typedef void (*NMBondManagerCallback)(NMBondManager *self, + NMBondManagerEventType event_type, + gpointer user_data); + +NMBondManager *nm_bond_manager_new(struct _NMPlatform *platform, + int ifindex, + const char *connection_uuid, + NMBondManagerCallback callback, + gpointer user_data); + +void nm_bond_manager_reapply(NMBondManager *self); + +void nm_bond_manager_destroy(NMBondManager *self); + +int nm_bond_manager_get_ifindex(NMBondManager *self); +const char *nm_bond_manager_get_connection_uuid(NMBondManager *self); +NMOptionBool nm_bond_manager_get_state(NMBondManager *self); + +#endif /* __NM_BOND_MANAGER_H__ */ diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c index 15667332..cd0e17fa 100644 --- a/src/core/nm-checkpoint.c +++ b/src/core/nm-checkpoint.c @@ -416,10 +416,10 @@ activate: } } else { /* The device was initially disconnected, deactivate any existing connection */ - _LOGD("rollback: disconnecting device"); if (nm_device_get_state(device) > NM_DEVICE_STATE_DISCONNECTED && nm_device_get_state(device) < NM_DEVICE_STATE_DEACTIVATING) { + _LOGD("rollback: disconnecting device"); nm_device_state_changed(device, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_USER_REQUESTED); diff --git a/src/core/nm-checkpoint.h b/src/core/nm-checkpoint.h index db33b6e7..b396acfe 100644 --- a/src/core/nm-checkpoint.h +++ b/src/core/nm-checkpoint.h @@ -10,7 +10,7 @@ #include "nm-dbus-interface.h" #define NM_TYPE_CHECKPOINT (nm_checkpoint_get_type()) -#define NM_CHECKPOINT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CHECKPOINT, NMCheckpoint)) +#define NM_CHECKPOINT(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CHECKPOINT, NMCheckpoint)) #define NM_CHECKPOINT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_CHECKPOINT, NMCheckpointClass)) #define NM_IS_CHECKPOINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_CHECKPOINT)) diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index 753e3fb5..ff44bc46 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -1125,10 +1125,13 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) gboolean default_found = FALSE; char **strv; - group = - internal ? NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS : NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS; - domain_prefix = internal ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN - : NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN; + if (internal) { + group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS; + domain_prefix = NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN; + } else { + group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS; + domain_prefix = NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN; + } domain_prefix_len = strlen(domain_prefix); if (!nm_config_keyfile_has_global_dns_config(keyfile, internal)) @@ -1191,8 +1194,7 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) if (strv) { nm_strv_cleanup(strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv[i]; i++) { - if (nm_utils_ipaddr_is_valid(AF_INET, strv[i]) - || nm_utils_ipaddr_is_valid(AF_INET6, strv[i])) + if (nm_inet_is_valid(AF_INET, strv[i]) || nm_inet_is_valid(AF_INET6, strv[i])) strv[j++] = strv[i]; else g_free(strv[i]); @@ -1231,7 +1233,7 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) default_found = TRUE; } - if (!default_found) { + if (!default_found && g_hash_table_size(dns_config->domains)) { nm_log_dbg(LOGD_CORE, "%s global DNS configuration is missing default domain, ignore it", internal ? "internal" : "user"); @@ -1328,8 +1330,7 @@ global_dns_domain_from_dbus(char *name, GVariant *variant) strv = g_variant_dup_strv(val, NULL); nm_strv_cleanup(strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv && strv[i]; i++) { - if (nm_utils_ipaddr_is_valid(AF_INET, strv[i]) - || nm_utils_ipaddr_is_valid(AF_INET6, strv[i])) + if (nm_inet_is_valid(AF_INET, strv[i]) || nm_inet_is_valid(AF_INET6, strv[i])) strv[j++] = strv[i]; else g_free(strv[i]); @@ -1462,21 +1463,23 @@ global_dns_equal(NMGlobalDnsConfig *old, NMGlobalDnsConfig *new) if ((!old->domains || !new->domains) && old->domains != new->domains) return FALSE; - if (g_hash_table_size(old->domains) != g_hash_table_size(new->domains)) + if (nm_g_hash_table_size(old->domains) != nm_g_hash_table_size(new->domains)) return FALSE; - g_hash_table_iter_init(&iter, old->domains); - while (g_hash_table_iter_next(&iter, &key, &value_old)) { - value_new = g_hash_table_lookup(new->domains, key); - if (!value_new) - return FALSE; + if (old->domains) { + g_hash_table_iter_init(&iter, old->domains); + while (g_hash_table_iter_next(&iter, &key, &value_old)) { + value_new = g_hash_table_lookup(new->domains, key); + if (!value_new) + return FALSE; - domain_old = value_old; - domain_new = value_new; + domain_old = value_old; + domain_new = value_new; - if (!nm_strv_equal(domain_old->options, domain_new->options) - || !nm_strv_equal(domain_old->servers, domain_new->servers)) - return FALSE; + if (!nm_strv_equal(domain_old->options, domain_new->options) + || !nm_strv_equal(domain_old->servers, domain_new->servers)) + return FALSE; + } } return TRUE; diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h index fdc7e1fc..e3dc90dd 100644 --- a/src/core/nm-config-data.h +++ b/src/core/nm-config-data.h @@ -31,7 +31,8 @@ typedef enum { /*****************************************************************************/ #define NM_TYPE_CONFIG_DATA (nm_config_data_get_type()) -#define NM_CONFIG_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONFIG_DATA, NMConfigData)) +#define NM_CONFIG_DATA(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONFIG_DATA, NMConfigData)) #define NM_CONFIG_DATA_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_CONFIG_DATA, NMConfigDataClass)) #define NM_IS_CONFIG_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_CONFIG_DATA)) diff --git a/src/core/nm-config.c b/src/core/nm-config.c index 62e4e7ea..b7445362 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -575,63 +575,63 @@ nm_config_cmd_line_options_add_to_entries(NMConfigCmdLineOptions *cli, GOptionCo { GOptionGroup *group; GOptionEntry config_options[] = { - {"config", + {"config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), DEFAULT_CONFIG_MAIN_FILE}, - {"config-dir", + {"config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), DEFAULT_CONFIG_DIR}, - {"system-config-dir", + {"system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), DEFAULT_SYSTEM_CONFIG_DIR}, - {"intern-config", + {"intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), DEFAULT_INTERN_CONFIG_FILE}, - {"state-file", + {"state-file", 0, 0, G_OPTION_ARG_FILENAME, &cli->state_file, N_("State file location"), DEFAULT_STATE_FILE}, - {"no-auto-default", + {"no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), DEFAULT_NO_AUTO_DEFAULT_FILE}, - {"plugins", + {"plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), NM_CONFIG_DEFAULT_MAIN_PLUGINS}, - {"configure-and-quit", + {"configure-and-quit", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_configure_and_quit, N_("Quit after initial configuration"), NULL}, - {"debug", + {"debug", 'd', 0, G_OPTION_ARG_NONE, @@ -639,29 +639,29 @@ nm_config_cmd_line_options_add_to_entries(NMConfigCmdLineOptions *cli, GOptionCo N_("Don't become a daemon, and log to stderr"), NULL}, - /* These three are hidden for now, and should eventually just go away. */ - {"connectivity-uri", + /* These three are hidden for now, and should eventually just go away. */ + {"connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com"}, - {"connectivity-interval", + {"connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), G_STRINGIFY(NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL)}, - {"connectivity-response", + {"connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE}, - {0}, + {0}, }; g_return_if_fail(opt_ctx); @@ -680,7 +680,7 @@ nm_config_cmd_line_options_add_to_entries(NMConfigCmdLineOptions *cli, GOptionCo /*****************************************************************************/ GKeyFile * -nm_config_create_keyfile() +nm_config_create_keyfile(void) { GKeyFile *keyfile; diff --git a/src/core/nm-config.h b/src/core/nm-config.h index 0dd159f4..d56770d0 100644 --- a/src/core/nm-config.h +++ b/src/core/nm-config.h @@ -12,7 +12,7 @@ #include "libnm-base/nm-config-base.h" #define NM_TYPE_CONFIG (nm_config_get_type()) -#define NM_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONFIG, NMConfig)) +#define NM_CONFIG(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONFIG, NMConfig)) #define NM_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_CONFIG, NMConfigClass)) #define NM_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_CONFIG)) #define NM_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_CONFIG)) diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index c0e77e35..aaf9d810 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -810,7 +810,7 @@ system_resolver_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer u for (iter = list; iter; iter = iter->next) { GInetAddress *a = iter->data; - char str_addr[NM_UTILS_INET_ADDRSTRLEN]; + char str_addr[NM_INET_ADDRSTRLEN]; int addr_family; switch (g_inet_address_get_family(a)) { @@ -835,7 +835,7 @@ system_resolver_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer u nm_str_buf_append_c(&strbuf_hosts, ','); nm_str_buf_append(&strbuf_hosts, - nm_utils_inet_ntop(addr_family, g_inet_address_to_bytes(a), str_addr)); + nm_inet_ntop(addr_family, g_inet_address_to_bytes(a), str_addr)); next:; } @@ -910,7 +910,7 @@ systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_da for (i = 0; i < no_addresses; i++) { gs_unref_variant GVariant *address = NULL; - char str_addr[NM_UTILS_INET_ADDRSTRLEN]; + char str_addr[NM_INET_ADDRSTRLEN]; const guchar *address_buf; g_variant_get_child(addresses, i, "(ii@ay)", &ifindex, &addr_family, &address); @@ -933,7 +933,7 @@ systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_da } else nm_str_buf_append_c(&strbuf_hosts, ','); - nm_str_buf_append(&strbuf_hosts, nm_utils_inet_ntop(addr_family, address_buf, str_addr)); + nm_str_buf_append(&strbuf_hosts, nm_inet_ntop(addr_family, address_buf, str_addr)); } if (strbuf_hosts.len == 0) { _LOG2D("systemd-resolve returned no usable IPv%c addresses", diff --git a/src/core/nm-connectivity.h b/src/core/nm-connectivity.h index 7b57a112..d9ea95c2 100644 --- a/src/core/nm-connectivity.h +++ b/src/core/nm-connectivity.h @@ -32,7 +32,7 @@ nm_connectivity_state_cmp(NMConnectivityState a, NMConnectivityState b) #define NM_TYPE_CONNECTIVITY (nm_connectivity_get_type()) #define NM_CONNECTIVITY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONNECTIVITY, NMConnectivity)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONNECTIVITY, NMConnectivity)) #define NM_CONNECTIVITY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_CONNECTIVITY, NMConnectivityClass)) #define NM_IS_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_CONNECTIVITY)) diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 4aad9414..500bffb9 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -58,7 +58,7 @@ G_STATIC_ASSERT(sizeof(NMUtilsTestFlags) <= sizeof(int)); static int _nm_utils_testing = 0; gboolean -nm_utils_get_testing_initialized() +nm_utils_get_testing_initialized(void) { NMUtilsTestFlags flags; @@ -69,7 +69,7 @@ nm_utils_get_testing_initialized() } NMUtilsTestFlags -nm_utils_get_testing() +nm_utils_get_testing(void) { NMUtilsTestFlags flags; @@ -2333,14 +2333,14 @@ nm_utils_log_connection_diff(NMConnection *connection, for (i = 0; i < sorted_hashes->len; i++) { LogConnectionSettingData *setting_data = - &g_array_index(sorted_hashes, LogConnectionSettingData, i); + &nm_g_array_index(sorted_hashes, LogConnectionSettingData, i); _log_connection_sort_names(setting_data, sorted_names); print_setting_header = TRUE; for (j = 0; j < sorted_names->len; j++) { char *str_conn, *str_diff; LogConnectionSettingItem *item = - &g_array_index(sorted_names, LogConnectionSettingItem, j); + &nm_g_array_index(sorted_names, LogConnectionSettingItem, j); str_conn = (item->diff_result & NM_SETTING_DIFF_RESULT_IN_A) ? _log_connection_get_property(setting_data->setting, item->item_name) @@ -2717,11 +2717,17 @@ _host_id_hash_v2(const guint8 *seed_arr, const UuidData *machine_id_data; char slen[100]; - /* - (stat -c '%s' /var/lib/NetworkManager/secret_key; - echo -n ' '; - cat /var/lib/NetworkManager/secret_key; - cat /etc/machine-id | tr -d '\n' | sed -n 's/[a-f0-9-]/\0/pg') | sha256sum + /* The following snippet generates the same (binary) host-id: + + ( + stat -c '%s' /var/lib/NetworkManager/secret_key | tr -d '\n'; + echo -n ' '; + cat /var/lib/NetworkManager/secret_key; + cat /etc/machine-id | tr -d '\n' | sed -n 's/[a-f0-9-]/\0/pg' + ) \ + | sha256sum \ + | awk '{print $1}' \ + | xxd -r -p */ nm_sprintf_buf(slen, "%" G_GSIZE_FORMAT " ", seed_len); @@ -3013,7 +3019,7 @@ nmtst_utils_host_id_pop(void) nm_log_dbg(LOGD_CORE, "nmtst: host-id pop"); - h = &g_array_index(nmtst_host_id_stack, HostIdData, nmtst_host_id_stack->len - 1); + h = &nm_g_array_index(nmtst_host_id_stack, HostIdData, nmtst_host_id_stack->len - 1); g_free((char *) h->host_id); g_array_set_size(nmtst_host_id_stack, nmtst_host_id_stack->len - 1u); @@ -3022,7 +3028,7 @@ nmtst_utils_host_id_pop(void) &host_id_static, h, nmtst_host_id_stack->len == 0u ? nmtst_host_id_static_0 - : nm_g_array_last(nmtst_host_id_stack, HostIdData))) + : &nm_g_array_last(nmtst_host_id_stack, HostIdData))) g_assert_not_reached(); } @@ -3864,7 +3870,7 @@ nm_utils_dhcp_client_id_duid(guint32 iaid, const guint8 *duid, gsize duid_len) guint8 type; guint32 iaid; guint8 duid[]; - } * client_id; + } *client_id; gsize total_size; /* the @duid must include the 16 bit duid-type and the data (of max 128 bytes). */ @@ -3914,7 +3920,7 @@ nm_utils_dhcp_client_id_systemd_node_specific_full(guint32 iaid, } en; }; } duid; - } * client_id; + } *client_id; guint64 u64; g_return_val_if_fail(machine_id, NULL); @@ -4193,7 +4199,7 @@ nm_utils_get_reverse_dns_domains_ip_6(const struct in6_addr *ip, guint8 plen, GP return; memcpy(&addr, ip, sizeof(struct in6_addr)); - nm_utils_ip6_address_clear_host_address(&addr, NULL, plen); + nm_ip6_addr_clear_host_address(&addr, NULL, plen); /* Number of nibbles to include in domains */ nibbles = (plen - 1) / 4 + 1; @@ -4338,7 +4344,7 @@ skip: result = g_new(char *, paths->len + 1); for (i = 0; i < paths->len; i++) - result[i] = g_array_index(paths, struct plugin_info, i).path; + result[i] = nm_g_array_index(paths, struct plugin_info, i).path; result[i] = NULL; g_array_free(paths, TRUE); @@ -4862,11 +4868,14 @@ typedef struct { int child_stdin; int child_stdout; + int child_stderr; GSource *input_source; GSource *output_source; + GSource *error_source; NMStrBuf in_buffer; NMStrBuf out_buffer; + NMStrBuf err_buffer; gsize out_buffer_offset; } HelperInfo; @@ -4902,13 +4911,17 @@ helper_info_free(gpointer data) nm_str_buf_destroy(&info->in_buffer); nm_str_buf_destroy(&info->out_buffer); + nm_str_buf_destroy(&info->err_buffer); nm_clear_g_source_inst(&info->input_source); nm_clear_g_source_inst(&info->output_source); + nm_clear_g_source_inst(&info->error_source); if (info->child_stdout != -1) nm_close(info->child_stdout); if (info->child_stdin != -1) nm_close(info->child_stdin); + if (info->child_stderr != -1) + nm_close(info->child_stderr); if (info->pid != -1) { nm_assert(info->pid > 1); @@ -4922,6 +4935,10 @@ static void helper_complete(HelperInfo *info, GError *error) { if (error) { + if (info->err_buffer.len > 0) { + _LOG2T(info, "stderr: %s", nm_str_buf_get_str(&info->err_buffer)); + } + nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id); g_task_return_error(info->task, error); @@ -5017,6 +5034,24 @@ helper_have_data(int fd, GIOCondition condition, gpointer user_data) return G_SOURCE_CONTINUE; } +static gboolean +helper_have_err_data(int fd, GIOCondition condition, gpointer user_data) +{ + HelperInfo *info = user_data; + gssize n_read; + + n_read = nm_utils_fd_read(fd, &info->err_buffer); + + if (n_read > 0) + return G_SOURCE_CONTINUE; + + nm_clear_g_source_inst(&info->error_source); + nm_close(info->child_stderr); + info->child_stderr = -1; + + return G_SOURCE_CONTINUE; +} + static void helper_child_terminated(GPid pid, int status, gpointer user_data) { @@ -5092,10 +5127,11 @@ nm_utils_spawn_helper(const char *const *args, &info->pid, &info->child_stdin, &info->child_stdout, - NULL, + &info->child_stderr, &error)) { info->child_stdin = -1; info->child_stdout = -1; + info->child_stderr = -1; info->pid = -1; g_task_return_error(info->task, g_error_new(NM_UTILS_ERROR, @@ -5124,9 +5160,11 @@ nm_utils_spawn_helper(const char *const *args, fcntl(info->child_stdin, F_SETFL, fd_flags | O_NONBLOCK); fd_flags = fcntl(info->child_stdout, F_GETFD, 0); fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK); + fd_flags = fcntl(info->child_stderr, F_GETFD, 0); + fcntl(info->child_stderr, F_SETFL, fd_flags | O_NONBLOCK); /* Watch process stdin */ - info->out_buffer = NM_STR_BUF_INIT(32, TRUE); + info->out_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, TRUE); for (arg = args; *arg; arg++) { nm_str_buf_append(&info->out_buffer, *arg); nm_str_buf_append_c(&info->out_buffer, '\0'); @@ -5140,7 +5178,7 @@ nm_utils_spawn_helper(const char *const *args, g_source_attach(info->output_source, g_main_context_get_thread_default()); /* Watch process stdout */ - info->in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + info->in_buffer = NM_STR_BUF_INIT(0, FALSE); info->input_source = nm_g_unix_fd_source_new(info->child_stdout, G_IO_IN | G_IO_ERR | G_IO_HUP, G_PRIORITY_DEFAULT, @@ -5149,6 +5187,16 @@ nm_utils_spawn_helper(const char *const *args, NULL); g_source_attach(info->input_source, g_main_context_get_thread_default()); + /* Watch process stderr */ + info->err_buffer = NM_STR_BUF_INIT(0, FALSE); + info->error_source = nm_g_unix_fd_source_new(info->child_stderr, + G_IO_IN | G_IO_ERR | G_IO_HUP, + G_PRIORITY_DEFAULT, + helper_have_err_data, + info, + NULL); + g_source_attach(info->error_source, g_main_context_get_thread_default()); + if (cancellable) { gulong signal_id; diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index 483af077..bc936496 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -112,7 +112,7 @@ nm_hash_update_in6addr_prefix(NMHashState *h, const struct in6_addr *addr, guint nm_assert(addr); - nm_utils_ip6_address_clear_host_address(&a, addr, plen); + nm_ip6_addr_clear_host_address(&a, addr, plen); /* we don't hash plen itself. The caller may want to do that.*/ nm_hash_update_in6addr(h, &a); } diff --git a/src/core/nm-dbus-manager.c b/src/core/nm-dbus-manager.c index 7fcbf6ca..af7de8c4 100644 --- a/src/core/nm-dbus-manager.c +++ b/src/core/nm-dbus-manager.c @@ -1077,7 +1077,7 @@ nm_dbus_manager_lookup_object(NMDBusManager *self, const char *path) if (!ptr) return NULL; - obj = (NMDBusObject *) (((char *) ptr) - G_STRUCT_OFFSET(NMDBusObject, internal)); + obj = NM_CAST_ALIGN(NMDBusObject, (((char *) ptr) - G_STRUCT_OFFSET(NMDBusObject, internal))); nm_assert(NM_IS_DBUS_OBJECT(obj)); return obj; } diff --git a/src/core/nm-dbus-manager.h b/src/core/nm-dbus-manager.h index d977f99f..b68161db 100644 --- a/src/core/nm-dbus-manager.h +++ b/src/core/nm-dbus-manager.h @@ -10,7 +10,8 @@ #include "nm-dbus-utils.h" #define NM_TYPE_DBUS_MANAGER (nm_dbus_manager_get_type()) -#define NM_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_DBUS_MANAGER, NMDBusManager)) +#define NM_DBUS_MANAGER(o) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_DBUS_MANAGER, NMDBusManager)) #define NM_DBUS_MANAGER_CLASS(k) \ (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) #define NM_IS_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), NM_TYPE_DBUS_MANAGER)) diff --git a/src/core/nm-dbus-object.h b/src/core/nm-dbus-object.h index df22bd92..2a0ff0ee 100644 --- a/src/core/nm-dbus-object.h +++ b/src/core/nm-dbus-object.h @@ -46,7 +46,8 @@ typedef struct { /*****************************************************************************/ #define NM_TYPE_DBUS_OBJECT (nm_dbus_object_get_type()) -#define NM_DBUS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DBUS_OBJECT, NMDBusObject)) +#define NM_DBUS_OBJECT(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DBUS_OBJECT, NMDBusObject)) #define NM_DBUS_OBJECT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DBUS_OBJECT, NMDBusObjectClass)) #define NM_IS_DBUS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DBUS_OBJECT)) diff --git a/src/core/nm-dbus-utils.c b/src/core/nm-dbus-utils.c index 096b647b..05eca84f 100644 --- a/src/core/nm-dbus-utils.c +++ b/src/core/nm-dbus-utils.c @@ -166,7 +166,7 @@ nm_dbus_utils_get_paths_for_clist(const CList *lst_head, i = 0; strv = g_new(const char *, n + 1); c_list_for_each (iter, lst_head) { - NMDBusObject *obj = (NMDBusObject *) (((const char *) iter) - member_offset); + NMDBusObject *obj = NM_CAST_ALIGN(NMDBusObject, (((char *) iter) - member_offset)); path = nm_dbus_object_get_path(obj); if (!path) { diff --git a/src/core/nm-default-daemon.h b/src/core/nm-default-daemon.h index 57d4c6af..f8270ef4 100644 --- a/src/core/nm-default-daemon.h +++ b/src/core/nm-default-daemon.h @@ -18,6 +18,7 @@ #include "nm-version.h" #include "nm-core-types.h" +#include "nm-errors.h" #include "nm-types.h" #include "libnm-log-core/nm-logging.h" diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c index 394a3a49..fca1dcdd 100644 --- a/src/core/nm-dhcp-config.c +++ b/src/core/nm-dhcp-config.c @@ -18,7 +18,7 @@ #define NM_TYPE_DHCP4_CONFIG (nm_dhcp4_config_get_type()) #define NM_DHCP4_CONFIG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4Config)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4Config)) #define NM_DHCP4_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) #define NM_IS_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP4_CONFIG)) @@ -33,7 +33,7 @@ static GType nm_dhcp4_config_get_type(void); #define NM_TYPE_DHCP6_CONFIG (nm_dhcp6_config_get_type()) #define NM_DHCP6_CONFIG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6Config)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6Config)) #define NM_DHCP6_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) #define NM_IS_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP6_CONFIG)) diff --git a/src/core/nm-dhcp-config.h b/src/core/nm-dhcp-config.h index cdca4ef1..e372ec81 100644 --- a/src/core/nm-dhcp-config.h +++ b/src/core/nm-dhcp-config.h @@ -9,7 +9,8 @@ /*****************************************************************************/ #define NM_TYPE_DHCP_CONFIG (nm_dhcp_config_get_type()) -#define NM_DHCP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_CONFIG, NMDhcpConfig)) +#define NM_DHCP_CONFIG(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_CONFIG, NMDhcpConfig)) #define NM_DHCP_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_CONFIG, NMDhcpConfigClass)) #define NM_IS_DHCP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_CONFIG)) diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index d3529ee4..cdc07dd6 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -8,6 +8,7 @@ #include "nm-dispatcher.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-aux-extern/nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -179,7 +180,6 @@ dump_ip_to_props(const NML3ConfigData *l3cd, int addr_family, GVariantBuilder *b const NMPObject *default_route; const char *const *strarr; const in_addr_t *ip4arr; - gconstpointer iparr; if (IS_IPv4) g_variant_builder_init(&int_builder, G_VARIANT_TYPE("aau")); @@ -223,14 +223,17 @@ dump_ip_to_props(const NML3ConfigData *l3cd, int addr_family, GVariantBuilder *b g_variant_builder_init(&int_builder, G_VARIANT_TYPE("au")); else g_variant_builder_init(&int_builder, G_VARIANT_TYPE("aay")); - iparr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &n); + strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &n); for (i = 0; i < n; i++) { + NMIPAddr a; + + if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) + continue; + if (IS_IPv4) - g_variant_builder_add(&int_builder, "u", ((const in_addr_t *) iparr)[i]); - else { - var1 = nm_g_variant_new_ay_in6addr(&(((const struct in6_addr *) iparr)[i])); - g_variant_builder_add(&int_builder, "@ay", var1); - } + g_variant_builder_add(&int_builder, "u", a.addr4); + else + g_variant_builder_add(&int_builder, "@ay", nm_g_variant_new_ay_in6addr(&a.addr6)); } g_variant_builder_add(builder, "{sv}", "nameservers", g_variant_builder_end(&int_builder)); @@ -426,7 +429,7 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) if (!ret) { NMLogLevel log_level = LOGL_DEBUG; - if (_nm_dbus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed")) { + if (nm_dbus_error_is(error, "org.freedesktop.systemd1.LoadFailed")) { g_dbus_error_strip_remote_error(error); log_level = LOGL_WARN; } @@ -465,7 +468,8 @@ static const char *action_table[] = {[NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ [NM_DISPATCHER_ACTION_DHCP_CHANGE_4] = NMD_ACTION_DHCP4_CHANGE, [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE, [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = - NMD_ACTION_CONNECTIVITY_CHANGE}; + NMD_ACTION_CONNECTIVITY_CHANGE, + [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY}; static const char * action_to_string(NMDispatcherAction action) diff --git a/src/core/nm-dispatcher.h b/src/core/nm-dispatcher.h index 73e0599a..30716399 100644 --- a/src/core/nm-dispatcher.h +++ b/src/core/nm-dispatcher.h @@ -21,7 +21,8 @@ typedef enum { NM_DISPATCHER_ACTION_VPN_DOWN, NM_DISPATCHER_ACTION_DHCP_CHANGE_4, NM_DISPATCHER_ACTION_DHCP_CHANGE_6, - NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE + NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, + NM_DISPATCHER_ACTION_REAPPLY, } NMDispatcherAction; #define NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4) \ diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 4bcde85f..f231583a 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -39,6 +39,71 @@ static const struct { /*****************************************************************************/ +static const char * +_nft_ifname_valid(const char *str) +{ + gsize i; + + /* `nft -f -` takes certain strings, like "device $IFNAME", but + * those strings are from a limited character set. Check that + * @str is valid according to those rules. + * + * src/scanner.l: + * digit [0-9] + * letter [a-zA-Z] + * string ({letter}|[_.])({letter}|{digit}|[/\-_\.])* + **/ + + if (!str || !str[0]) + return NULL; + + for (i = 0; str[i]; i++) { + switch (str[i]) { + case 'a' ... 'z': + case 'A' ... 'Z': + case '_': + case '.': + continue; + case '0' ... '9': + case '/': + case '-': + if (i == 0) + return NULL; + continue; + default: + return NULL; + } + } + if (i >= NMP_IFNAMSIZ) + return NULL; + + return str; +} + +static const char * +_strbuf_set_sanitized(NMStrBuf *strbuf, const char *prefix, const char *str_to_sanitize) +{ + nm_str_buf_reset(strbuf); + + if (prefix) + nm_str_buf_append(strbuf, prefix); + + for (; str_to_sanitize[0] != '\0'; str_to_sanitize++) { + const char ch = str_to_sanitize[0]; + + if (g_ascii_isalpha(ch) || g_ascii_isdigit(ch)) { + nm_str_buf_append_c(strbuf, ch); + continue; + } + nm_str_buf_append_c(strbuf, '_'); + nm_str_buf_append_c_hex(strbuf, ch, FALSE); + } + + return nm_str_buf_get_str(strbuf); +} + +/*****************************************************************************/ + #define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1) static const char * @@ -50,12 +115,12 @@ _share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR in_addr_t netmask; int l; - netmask = _nm_utils_ip4_prefix_to_netmask(plen); + netmask = nm_ip4_addr_netmask_from_prefix(plen); l = g_snprintf(buf, _SHARE_IPTABLES_SUBNET_TO_STR_LEN, "%s/%u", - _nm_utils_inet4_ntop(addr & netmask, buf_addr), + nm_inet4_ntop(addr & netmask, buf_addr), plen); nm_assert(l < _SHARE_IPTABLES_SUBNET_TO_STR_LEN); return buf; @@ -693,6 +758,189 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, /*****************************************************************************/ +GBytes * +nm_firewall_nft_stdio_mlag(gboolean up, + const char *bond_ifname, + const char *const *bond_ifnames_down, + const char *const *active_members, + const char *const *previous_members) +{ + nm_auto_str_buf NMStrBuf strbuf_table_name = + NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + const char *table_name; + gsize i; + + if (NM_MORE_ASSERTS > 10 && active_members) { + /* No duplicates. We make certain assumptions here, and we don't + * want to check that there are no duplicates. The caller must take + * care of this. */ + for (i = 0; active_members[i]; i++) + nm_assert(!nm_strv_contains(&active_members[i + 1], -1, active_members[i])); + } + + /* If an interface gets renamed, we need to update the nft tables. Since one nft + * invocation is atomic, it is reasonable to drop the previous tables(s) at the + * same time when creating the new one. */ + for (; bond_ifnames_down && bond_ifnames_down[0]; bond_ifnames_down++) { + if (nm_streq(bond_ifname, bond_ifnames_down[0])) + continue; + table_name = _strbuf_set_sanitized(&strbuf_table_name, "nm-mlag-", bond_ifnames_down[0]); + _fw_nft_append_cmd_table(&strbuf, "netdev", table_name, FALSE); + } + + table_name = _strbuf_set_sanitized(&strbuf_table_name, "nm-mlag-", bond_ifname); + + _fw_nft_append_cmd_table(&strbuf, "netdev", table_name, up); + + if (up) { + nm_auto_str_buf NMStrBuf strbuf_1 = + NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); + const gsize n_active_members = NM_PTRARRAY_LEN(active_members); + + if (!_nft_ifname_valid(bond_ifname)) { + /* We cannot meaningfully express this interface name. Ignore all chains + * and only create an empty table. */ + goto out; + } + + for (; previous_members && previous_members[0]; previous_members++) { + const char *previous_member = previous_members[0]; + const char *chain_name; + + /* The caller already ensures that the previous member is not part of the new + * active members. Avoid the overhead of checking, and assert against that. */ + nm_assert(!nm_strv_contains(active_members, n_active_members, previous_member)); + + if (!_nft_ifname_valid(previous_member)) + continue; + + chain_name = _strbuf_set_sanitized(&strbuf_1, "rx-drop-bc-mc-", previous_member); + + /* We want atomically update our table, however, we don't want to delete + * and recreate it, because then the sets get lost (which we don't want). + * + * Instead, we only "add && flush" the table, which removes all rules from + * the chain. However, as our active-members change, we want to delete + * the obsolete chains too. + * + * nft has no way to delete all chains in a table, we have to name + * them one by one. So we keep track of active members that we had + * in the past, and which are now no longer in use. For those previous + * members we delete the chains (again, with the "add && delete" dance + * to avoid failure deleting a non-existing chain (in case our tracking + * is wrong or somebody else modified the table in the meantime). + * + * We need to track the previous members, because we don't want to first + * ask nft which chains exist. Doing that would be cumbersome as we would + * have to do one async program invocation and parse stdout. */ + _append(&strbuf, + "add chain netdev %s %s {" + " type filter hook ingress device %s priority filter; " + "}", + table_name, + chain_name, + previous_member); + _append(&strbuf, "delete chain netdev %s %s", table_name, chain_name); + } + + /* OVS SLB rule 1 + * + * "Open vSwitch avoids packet duplication by accepting multicast and broadcast + * packets on only the active member, and dropping multicast and broadcast + * packets on all other members." + * + * primary is first member, we drop on all others */ + for (i = 0; i < n_active_members; i++) { + const char *active_member = active_members[i]; + const char *chain_name; + + if (!_nft_ifname_valid(active_member)) + continue; + + chain_name = _strbuf_set_sanitized(&strbuf_1, "rx-drop-bc-mc-", active_member); + + _append(&strbuf, + "add chain netdev %s %s {" + " type filter hook ingress device %s priority filter; " + "}", + table_name, + chain_name, + active_member); + + if (i == 0) { + _append(&strbuf, "delete chain netdev %s %s", table_name, chain_name); + continue; + } + + _append(&strbuf, + "add rule netdev %s %s pkttype {" + " broadcast, multicast " + "} counter drop", + table_name, + chain_name); + } + + /* OVS SLB rule 2 + * + * "Open vSwitch deals with this case by dropping packets received on any SLB + * bonded link that have a source MAC+VLAN that has been learned on any other + * port." + */ + _append(&strbuf, + "add set netdev %s macset-tagged {" + " typeof ether saddr . vlan id; flags timeout; " + "}", + table_name); + _append(&strbuf, + "add set netdev %s macset-untagged {" + " typeof ether saddr; flags timeout;" + "}", + table_name); + + _append(&strbuf, + "add chain netdev %s tx-snoop-source-mac {" + " type filter hook egress device %s priority filter; " + "}", + table_name, + bond_ifname); + _append(&strbuf, + "add rule netdev %s tx-snoop-source-mac set update ether saddr . vlan id" + " timeout 5s @macset-tagged counter return" + "", /* tagged */ + table_name); + _append(&strbuf, + "add rule netdev %s tx-snoop-source-mac set update ether saddr" + " timeout 5s @macset-untagged counter" + "", /* untagged*/ + table_name); + + _append(&strbuf, + "add chain netdev %s rx-drop-looped-packets {" + " type filter hook ingress device %s priority filter; " + "}", + table_name, + bond_ifname); + _append(&strbuf, + "add rule netdev %s rx-drop-looped-packets ether saddr . vlan id" + " @macset-tagged counter drop", + table_name); + _append(&strbuf, + "add rule netdev %s rx-drop-looped-packets ether type vlan counter return" + "", /* avoid looking up tagged packets in untagged table */ + table_name); + _append(&strbuf, + "add rule netdev %s rx-drop-looped-packets ether saddr @macset-untagged" + " counter drop", + table_name); + } + +out: + return nm_str_buf_finalize_to_gbytes(&strbuf); +} + +/*****************************************************************************/ + struct _NMFirewallConfig { char *ip_iface; in_addr_t addr; diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h index 9d883fea..ca138ccf 100644 --- a/src/core/nm-firewall-utils.h +++ b/src/core/nm-firewall-utils.h @@ -35,4 +35,10 @@ void nm_firewall_nft_call(GBytes *stdin_buf, gboolean nm_firewall_nft_call_finish(GAsyncResult *result, GError **error); +GBytes *nm_firewall_nft_stdio_mlag(gboolean up, + const char *bond_ifname, + const char *const *bond_ifnames_down, + const char *const *active_members, + const char *const *previous_members); + #endif /* __NM_FIREWALL_UTILS_H__ */ diff --git a/src/core/nm-firewalld-manager.h b/src/core/nm-firewalld-manager.h index a7e71486..1e8f9a42 100644 --- a/src/core/nm-firewalld-manager.h +++ b/src/core/nm-firewalld-manager.h @@ -8,7 +8,7 @@ #define NM_TYPE_FIREWALLD_MANAGER (nm_firewalld_manager_get_type()) #define NM_FIREWALLD_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManager)) #define NM_FIREWALLD_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManagerClass)) #define NM_IS_FIREWALLD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_FIREWALLD_MANAGER)) diff --git a/src/core/nm-hostname-manager.c b/src/core/nm-hostname-manager.c index ba0c6c9d..b036590f 100644 --- a/src/core/nm-hostname-manager.c +++ b/src/core/nm-hostname-manager.c @@ -99,53 +99,32 @@ _file_monitor_new(const char *path) /*****************************************************************************/ -#if defined(HOSTNAME_PERSIST_GENTOO) static char * -read_hostname_gentoo(const char *path) +read_hostname(const char *path, gboolean is_gentoo) { - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - const char *tmp; - guint i; + gs_free char *contents = NULL; + gs_free const char **all_lines = NULL; + const char *tmp; + gsize i; if (!g_file_get_contents(path, &contents, NULL, NULL)) return NULL; - all_lines = g_strsplit(contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip(all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - if (g_str_has_prefix(all_lines[i], "hostname=")) { - tmp = &all_lines[i][NM_STRLEN("hostname=")]; - return g_shell_unquote(tmp, NULL); + all_lines = nm_strsplit_set_full(contents, "\n", NM_STRSPLIT_SET_FLAGS_STRSTRIP); + for (i = 0; (tmp = all_lines[i]); i++) { + if (is_gentoo) { + if (!NM_STR_HAS_PREFIX(tmp, "hostname=")) + continue; + tmp = &tmp[NM_STRLEN("hostname=")]; + } else { + if (tmp[0] == '#') + continue; } + nm_assert(tmp && tmp[0] != '\0'); + return g_shell_unquote(tmp, NULL); } return NULL; } -#endif - -#if defined(HOSTNAME_PERSIST_SLACKWARE) -static char * -read_hostname_slackware(const char *path) -{ - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - guint i = 0; - - if (!g_file_get_contents(path, &contents, NULL, NULL)) - return NULL; - - all_lines = g_strsplit(contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip(all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - return g_shell_unquote(&all_lines[i][0], NULL); - } - return NULL; -} -#endif #if defined(HOSTNAME_PERSIST_SUSE) static gboolean @@ -237,10 +216,11 @@ _set_hostname_read_file(NMHostnameManager *self) #endif #if defined(HOSTNAME_PERSIST_GENTOO) - hostname = read_hostname_gentoo(HOSTNAME_FILE); + hostname = read_hostname(HOSTNAME_FILE, TRUE); #elif defined(HOSTNAME_PERSIST_SLACKWARE) - hostname = read_hostname_slackware(HOSTNAME_FILE); + hostname = read_hostname(HOSTNAME_FILE, FALSE); #else + (void) read_hostname; if (g_file_get_contents(HOSTNAME_FILE, &hostname, NULL, NULL)) g_strchomp(hostname); #endif @@ -433,11 +413,11 @@ _write_hostname_on_idle_cb(gpointer user_data, GCancellable *cancellable) } void -nm_hostname_manager_write_hostname(NMHostnameManager *self, - const char *hostname, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +nm_hostname_manager_set_static_hostname(NMHostnameManager *self, + const char *hostname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { NMHostnameManagerPrivate *priv; GTask *task; @@ -446,8 +426,11 @@ nm_hostname_manager_write_hostname(NMHostnameManager *self, priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self); - task = - nm_g_task_new(self, cancellable, nm_hostname_manager_write_hostname, callback, user_data); + task = nm_g_task_new(self, + cancellable, + nm_hostname_manager_set_static_hostname, + callback, + user_data); g_task_set_task_data(task, g_strdup(hostname), g_free); @@ -467,12 +450,12 @@ nm_hostname_manager_write_hostname(NMHostnameManager *self, } gboolean -nm_hostname_manager_write_hostname_finish(NMHostnameManager *self, - GAsyncResult *result, - GError **error) +nm_hostname_manager_set_static_hostname_finish(NMHostnameManager *self, + GAsyncResult *result, + GError **error) { g_return_val_if_fail(NM_IS_HOSTNAME_MANAGER(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_hostname_manager_write_hostname), + g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_hostname_manager_set_static_hostname), FALSE); return g_task_propagate_boolean(G_TASK(result), error); diff --git a/src/core/nm-hostname-manager.h b/src/core/nm-hostname-manager.h index 31596819..54818da3 100644 --- a/src/core/nm-hostname-manager.h +++ b/src/core/nm-hostname-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_HOSTNAME_MANAGER (nm_hostname_manager_get_type()) #define NM_HOSTNAME_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManager)) #define NM_HOSTNAME_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass)) #define NM_IS_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_HOSTNAME_MANAGER)) @@ -36,15 +36,15 @@ NMHostnameManager *nm_hostname_manager_get(void); const char *nm_hostname_manager_get_static_hostname(NMHostnameManager *self); -void nm_hostname_manager_write_hostname(NMHostnameManager *self, - const char *hostname, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void nm_hostname_manager_set_static_hostname(NMHostnameManager *self, + const char *hostname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); -gboolean nm_hostname_manager_write_hostname_finish(NMHostnameManager *self, - GAsyncResult *result, - GError **error); +gboolean nm_hostname_manager_set_static_hostname_finish(NMHostnameManager *self, + GAsyncResult *result, + GError **error); void nm_hostname_manager_set_transient_hostname(NMHostnameManager *self, const char *hostname, diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index b191b54b..bec67d9a 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -10,6 +10,7 @@ #include <linux/rtnetlink.h> +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "nm-l3cfg.h" #include "NetworkManagerUtils.h" @@ -90,7 +91,7 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec NMIPConfig *self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); const int addr_family = nm_ip_config_get_addr_family(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; const char *const *strv; guint len; int v_i; @@ -108,7 +109,7 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec NMP_OBJECT_CAST_IP_ROUTE(priv->v_gateway.best_default_route)); g_value_set_variant( value, - g_variant_new_string(nm_utils_inet_ntop(addr_family, gateway, sbuf_addr))); + g_variant_new_string(nm_inet_ntop(addr_family, gateway, sbuf_addr))); } else g_value_set_variant(value, nm_g_variant_singleton_s_empty()); break; @@ -333,9 +334,10 @@ get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe { NMIPConfig *self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + char addr_str[NM_INET_ADDRSTRLEN]; GVariantBuilder builder; const in_addr_t *addrs; + const char *const *strarr; guint len; guint i; @@ -347,28 +349,37 @@ get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe g_value_set_variant(value, priv->v_routes); break; case PROP_IP4_NAMESERVERS: - addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET, &len); - g_value_set_variant(value, - (len == 0) ? nm_g_variant_singleton_au() - : nm_g_variant_new_au(addrs, len)); - break; case PROP_IP4_NAMESERVER_DATA: - addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET, &len); - if (len == 0) - g_value_set_variant(value, nm_g_variant_singleton_aaLsvI()); - else { - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); + strarr = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET, &len); + if (len == 0) { + g_value_set_variant(value, + (prop_id == PROP_IP4_NAMESERVERS) + ? nm_g_variant_singleton_au() + : nm_g_variant_singleton_aaLsvI()); + } else { + if (prop_id == PROP_IP4_NAMESERVERS) + g_variant_builder_init(&builder, G_VARIANT_TYPE("au")); + else + g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); for (i = 0; i < len; i++) { - GVariantBuilder nested_builder; + in_addr_t a; - _nm_utils_inet4_ntop(addrs[i], addr_str); + if (!nm_utils_dnsname_parse_assert(AF_INET, strarr[i], NULL, &a, NULL)) + continue; - g_variant_builder_init(&nested_builder, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(&nested_builder, - "{sv}", - "address", - g_variant_new_string(addr_str)); - g_variant_builder_add(&builder, "a{sv}", &nested_builder); + if (prop_id == PROP_IP4_NAMESERVERS) + g_variant_builder_add(&builder, "u", a); + else { + GVariantBuilder nested_builder; + + nm_inet4_ntop(a, addr_str); + g_variant_builder_init(&nested_builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&nested_builder, + "{sv}", + "address", + g_variant_new_string(addr_str)); + g_variant_builder_add(&builder, "a{sv}", &nested_builder); + } } g_value_take_variant(value, g_variant_builder_end(&builder)); @@ -387,7 +398,7 @@ get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe else { g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); for (i = 0; i < len; i++) - g_variant_builder_add(&builder, "s", _nm_utils_inet4_ntop(addrs[i], addr_str)); + g_variant_builder_add(&builder, "s", nm_inet4_ntop(addrs[i], addr_str)); g_value_take_variant(value, g_variant_builder_end(&builder)); } break; @@ -498,77 +509,6 @@ nm_ip4_config_class_init(NMIP4ConfigClass *klass) g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip4, obj_properties_ip4); } -void -nm_ip_config_dns_hash(const NML3ConfigData *l3cd, GChecksum *sum, int addr_family) -{ - guint i; - int val; - const char *const *nameservers; - const in_addr_t *wins; - const char *const *domains; - const char *const *searches; - const char *const *options; - guint num_nameservers; - guint num_wins; - guint num_domains; - guint num_searches; - guint num_options; - - g_return_if_fail(l3cd); - g_return_if_fail(sum); - - nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers); - for (i = 0; i < num_nameservers; i++) { - g_checksum_update(sum, - nm_ip_addr_from_packed_array(addr_family, nameservers, i), - nm_utils_addr_family_to_size(addr_family)); - } - - if (addr_family == AF_INET) { - wins = nm_l3_config_data_get_wins(l3cd, &num_wins); - for (i = 0; i < num_wins; i++) - g_checksum_update(sum, (guint8 *) &wins[i], 4); - } - - domains = nm_l3_config_data_get_domains(l3cd, addr_family, &num_domains); - for (i = 0; i < num_domains; i++) { - g_checksum_update(sum, (const guint8 *) domains[i], strlen(domains[i])); - } - - searches = nm_l3_config_data_get_searches(l3cd, addr_family, &num_searches); - for (i = 0; i < num_searches; i++) { - g_checksum_update(sum, (const guint8 *) searches[i], strlen(searches[i])); - } - - options = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num_options); - for (i = 0; i < num_options; i++) { - g_checksum_update(sum, (const guint8 *) options[i], strlen(options[i])); - } - - val = nm_l3_config_data_get_mdns(l3cd); - if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT) - g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); - - val = nm_l3_config_data_get_llmnr(l3cd); - if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT) - g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); - - val = nm_l3_config_data_get_dns_over_tls(l3cd); - if (val != NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT) - g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); - - /* FIXME(ip-config-checksum): the DNS priority should be considered relevant - * and added into the checksum as well, but this can't be done right now - * because in the DNS manager we rely on the fact that an empty - * configuration (i.e. just created) has a zero checksum. This is needed to - * avoid rewriting resolv.conf when there is no change. - * - * The DNS priority initial value depends on the connection type (VPN or - * not), so it's a bit difficult to add it to checksum maintaining the - * assumption of checksum(empty)=0 - */ -} - /*****************************************************************************/ /* public */ @@ -630,12 +570,12 @@ static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { static void get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMIPConfig *self = NM_IP_CONFIG(object); - NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); - GVariantBuilder builder; - guint len; - guint i; - const struct in6_addr *addrs; + NMIPConfig *self = NM_IP_CONFIG(object); + NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + GVariantBuilder builder; + guint len; + guint i; + const char *const *strarr; switch (prop_id) { case PROP_IP6_ADDRESSES: @@ -645,13 +585,19 @@ get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe g_value_set_variant(value, priv->v_routes); break; case PROP_IP6_NAMESERVERS: - addrs = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET6, &len); + strarr = nm_l3_config_data_get_nameservers(priv->l3cd, AF_INET6, &len); if (len == 0) g_value_set_variant(value, nm_g_variant_singleton_aay()); else { g_variant_builder_init(&builder, G_VARIANT_TYPE("aay")); - for (i = 0; i < len; i++) - g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&addrs[i])); + for (i = 0; i < len; i++) { + struct in6_addr a; + + if (!nm_utils_dnsname_parse_assert(AF_INET6, strarr[i], NULL, &a, NULL)) + continue; + + g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&a)); + } g_value_take_variant(value, g_variant_builder_end(&builder)); } break; @@ -736,8 +682,8 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; GParamSpec *changed_params[8]; guint n_changed_params = 0; - const char *const *strv; - const char *const *strv_old; + const char *const *strarr; + const char *const *strarr_old; gconstpointer addrs; gconstpointer addrs_old; guint len; @@ -748,9 +694,9 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) l3cd_old = g_steal_pointer(&priv->l3cd); priv->l3cd = nm_l3_config_data_ref(l3cd); - addrs_old = nm_l3_config_data_get_nameservers(l3cd_old, addr_family, &len_old); - addrs = nm_l3_config_data_get_nameservers(priv->l3cd, addr_family, &len); - if (!nm_memeq_n(addrs_old, len_old, addrs, len, nm_utils_addr_family_to_size(addr_family))) { + strarr_old = nm_l3_config_data_get_nameservers(l3cd_old, addr_family, &len_old); + strarr = nm_l3_config_data_get_nameservers(priv->l3cd, addr_family, &len); + if (!nm_strv_equal_n(strarr_old, len_old, strarr, len)) { if (IS_IPv4) { changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_NAMESERVER_DATA]; changed_params[n_changed_params++] = obj_properties_ip4[PROP_IP4_NAMESERVERS]; @@ -758,14 +704,14 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) changed_params[n_changed_params++] = obj_properties_ip6[PROP_IP6_NAMESERVERS]; } - strv_old = nm_l3_config_data_get_domains(l3cd_old, addr_family, &len_old); - strv = nm_l3_config_data_get_domains(priv->l3cd, addr_family, &len); - if (!nm_strv_equal_n(strv, len, strv_old, len_old)) + strarr_old = nm_l3_config_data_get_domains(l3cd_old, addr_family, &len_old); + strarr = nm_l3_config_data_get_domains(priv->l3cd, addr_family, &len); + if (!nm_strv_equal_n(strarr, len, strarr_old, len_old)) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DOMAINS]; - strv_old = nm_l3_config_data_get_searches(l3cd_old, addr_family, &len_old); - strv = nm_l3_config_data_get_searches(priv->l3cd, addr_family, &len); - if (!nm_strv_equal_n(strv, len, strv_old, len_old)) + strarr_old = nm_l3_config_data_get_searches(l3cd_old, addr_family, &len_old); + strarr = nm_l3_config_data_get_searches(priv->l3cd, addr_family, &len); + if (!nm_strv_equal_n(strarr, len, strarr_old, len_old)) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_SEARCHES]; v_i_old = nm_l3_config_data_get_dns_priority_or_default(l3cd_old, addr_family); @@ -773,9 +719,9 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) if (v_i != v_i_old) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_PRIORITY]; - strv_old = nm_l3_config_data_get_dns_options(l3cd_old, addr_family, &len); - strv = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len); - if (!nm_strv_equal_n(strv, len, strv_old, len_old)) + strarr_old = nm_l3_config_data_get_dns_options(l3cd_old, addr_family, &len); + strarr = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len); + if (!nm_strv_equal_n(strarr, len, strarr_old, len_old)) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_OPTIONS]; if (IS_IPv4) { diff --git a/src/core/nm-ip-config.h b/src/core/nm-ip-config.h index 68103cf7..0dcea83b 100644 --- a/src/core/nm-ip-config.h +++ b/src/core/nm-ip-config.h @@ -12,7 +12,7 @@ /*****************************************************************************/ #define NM_TYPE_IP_CONFIG (nm_ip_config_get_type()) -#define NM_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_CONFIG, NMIPConfig)) +#define NM_IP_CONFIG(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_CONFIG, NMIPConfig)) #define NM_IP_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IP_CONFIG, NMIPConfigClass)) #define NM_IS_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IP_CONFIG)) @@ -51,8 +51,6 @@ NMIPConfig *nm_ip_config_new(int addr_family, NML3Cfg *l3cfg); void nm_ip_config_take_and_unexport_on_idle(NMIPConfig *self_take); -void nm_ip_config_dns_hash(const NML3ConfigData *l3cd, GChecksum *sum, int addr_family); - /*****************************************************************************/ static inline NML3Cfg * diff --git a/src/core/nm-keep-alive.h b/src/core/nm-keep-alive.h index 7737c17a..14378d25 100644 --- a/src/core/nm-keep-alive.h +++ b/src/core/nm-keep-alive.h @@ -7,7 +7,7 @@ #define __NETWORKMANAGER_KEEP_ALIVE_H__ #define NM_TYPE_KEEP_ALIVE (nm_keep_alive_get_type()) -#define NM_KEEP_ALIVE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_KEEP_ALIVE, NMKeepAlive)) +#define NM_KEEP_ALIVE(o) (_NM_G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_KEEP_ALIVE, NMKeepAlive)) #define NM_KEEP_ALIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_KEEP_ALIVE, NMKeepAliveClass)) #define NM_KEEP_ALIVE_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS((o), NM_TYPE_KEEP_ALIVE, NMKeepAliveClass)) diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index bcd0b62a..17bb9db8 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -5,7 +5,7 @@ #include "nm-l3-config-data.h" #include <linux/if.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include <linux/rtnetlink.h> #include "libnm-core-intern/nm-core-internal.h" @@ -67,10 +67,10 @@ struct _NML3ConfigData { union { struct { - GArray *nameservers_6; - GArray *nameservers_4; + GPtrArray *nameservers_6; + GPtrArray *nameservers_4; }; - GArray *nameservers_x[2]; + GPtrArray *nameservers_x[2]; }; union { @@ -269,17 +269,6 @@ _garray_inaddr_get(GArray *arr, guint *out_len) return arr->data; } -static gconstpointer -_garray_inaddr_at(GArray *arr, gboolean IS_IPv4, guint idx) -{ - nm_assert(arr); - nm_assert(idx < arr->len); - - if (IS_IPv4) - return &g_array_index(arr, in_addr_t, idx); - return &g_array_index(arr, struct in6_addr, idx); -} - static gboolean _garray_inaddr_add(GArray **p_arr, int addr_family, gconstpointer addr) { @@ -352,7 +341,7 @@ nm_l3_config_data_log(const NML3ConfigData *self, NMLogDomain log_domain) { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; int IS_IPv4; guint i; @@ -480,13 +469,11 @@ nm_l3_config_data_log(const NML3ConfigData *self, self->dns_priority_x[IS_IPv4]); } - for (i = 0; i < nm_g_array_len(self->nameservers_x[IS_IPv4]); i++) { + for (i = 0; i < nm_g_ptr_array_len(self->nameservers_x[IS_IPv4]); i++) { _L("nameserver%c[%u]: %s", nm_utils_addr_family_to_char(addr_family), i, - nm_utils_inet_ntop(addr_family, - _garray_inaddr_at(self->nameservers_x[IS_IPv4], IS_IPv4, i), - sbuf_addr)); + (char *) self->nameservers_x[IS_IPv4]->pdata[i]); } for (i = 0; i < nm_g_ptr_array_len(self->domains_x[IS_IPv4]); i++) { @@ -514,12 +501,12 @@ nm_l3_config_data_log(const NML3ConfigData *self, for (i = 0; i < nm_g_array_len(self->wins); i++) { _L("wins[%u]: %s", i, - _nm_utils_inet4_ntop(g_array_index(self->wins, in_addr_t, i), sbuf_addr)); + nm_inet4_ntop(nm_g_array_index(self->wins, in_addr_t, i), sbuf_addr)); } for (i = 0; i < nm_g_array_len(self->nis_servers); i++) { _L("nis-server[%u]: %s", i, - _nm_utils_inet4_ntop(g_array_index(self->nis_servers, in_addr_t, i), sbuf_addr)); + nm_inet4_ntop(nm_g_array_index(self->nis_servers, in_addr_t, i), sbuf_addr)); } if (self->nis_domain) _L("nis-domain: %s", self->nis_domain->str); @@ -621,8 +608,7 @@ nm_l3_config_data_log(const NML3ConfigData *self, static gboolean _route_valid_4(const NMPlatformIP4Route *r) { - return r && r->plen <= 32 - && r->network == nm_utils_ip4_address_clear_host_address(r->network, r->plen); + return r && r->plen <= 32 && r->network == nm_ip4_addr_clear_host_address(r->network, r->plen); } static gboolean @@ -632,7 +618,7 @@ _route_valid_6(const NMPlatformIP6Route *r) return r && r->plen <= 128 && (memcmp(&r->network, - nm_utils_ip6_address_clear_host_address(&n, &r->network, r->plen), + nm_ip6_addr_clear_host_address(&n, &r->network, r->plen), sizeof(n)) == 0); } @@ -793,8 +779,8 @@ nm_l3_config_data_unref(const NML3ConfigData *self) nm_clear_pointer(&mutable->dhcp_lease_4, nm_dhcp_lease_unref); nm_clear_pointer(&mutable->dhcp_lease_6, nm_dhcp_lease_unref); - nm_clear_pointer(&mutable->nameservers_4, g_array_unref); - nm_clear_pointer(&mutable->nameservers_6, g_array_unref); + nm_clear_pointer(&mutable->nameservers_4, g_ptr_array_unref); + nm_clear_pointer(&mutable->nameservers_6, g_ptr_array_unref); nm_clear_pointer(&mutable->domains_4, g_ptr_array_unref); nm_clear_pointer(&mutable->domains_6, g_ptr_array_unref); @@ -1422,7 +1408,7 @@ _check_and_add_domain(GPtrArray **p_arr, const char *domain) return TRUE; } -gconstpointer +const char *const * nm_l3_config_data_get_nameservers(const NML3ConfigData *self, int addr_family, guint *out_len) { nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); @@ -1434,33 +1420,68 @@ nm_l3_config_data_get_nameservers(const NML3ConfigData *self, int addr_family, g return NULL; } - return _garray_inaddr_get(self->nameservers_x[NM_IS_IPv4(addr_family)], out_len); + return nm_strv_ptrarray_get_unsafe(self->nameservers_x[NM_IS_IPv4(addr_family)], out_len); } gboolean -nm_l3_config_data_add_nameserver(NML3ConfigData *self, - int addr_family, - gconstpointer /* (const NMIPAddr *) */ nameserver) +nm_l3_config_data_add_nameserver(NML3ConfigData *self, int addr_family, const char *nameserver) { + GPtrArray **p_arr; + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert_addr_family(addr_family); nm_assert(nameserver); - return _garray_inaddr_add(&self->nameservers_x[NM_IS_IPv4(addr_family)], - addr_family, - nameserver); + if (NM_MORE_ASSERTS > 5) { + gs_free char *s_free = NULL; + + nm_assert( + nm_streq0(nm_utils_dnsname_normalize(addr_family, nameserver, &s_free), nameserver)); + } + + p_arr = &self->nameservers_x[NM_IS_IPv4(addr_family)]; + + if (nm_strv_ptrarray_contains(*p_arr, nameserver)) + return FALSE; + + nm_strv_ptrarray_add_string_dup(nm_strv_ptrarray_ensure(p_arr), nameserver); + return TRUE; +} + +gboolean +nm_l3_config_data_add_nameserver_detail(NML3ConfigData *self, + int addr_family, + gconstpointer addr_bin, + const char *server_name) +{ + gs_free char *s_free = NULL; + char *s; + gsize l; + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert_addr_family(addr_family); + nm_assert(addr_bin); + + l = (NM_INET_ADDRSTRLEN + 2u) + (server_name ? strlen(server_name) : 0u); + + s = nm_malloc_maybe_a(300, l, &s_free); + + if (!nm_utils_dnsname_construct(addr_family, addr_bin, server_name, s, l)) + nm_assert_not_reached(); + + return nm_l3_config_data_add_nameserver(self, addr_family, s); } gboolean nm_l3_config_data_clear_nameservers(NML3ConfigData *self, int addr_family) { - gs_unref_array GArray *old = NULL; + gs_unref_ptrarray GPtrArray *old = NULL; nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert_addr_family(addr_family); old = g_steal_pointer(&self->nameservers_x[NM_IS_IPv4(addr_family)]); - return (nm_g_array_len(old) > 0); + return (nm_g_ptr_array_len(old) > 0); } const in_addr_t * @@ -2185,8 +2206,7 @@ _dedup_multi_index_cmp(const NML3ConfigData *a, NM_CMP_DIRECT(ra.metric, rb.metric); NM_CMP_DIRECT(ra.plen, rb.plen); - NM_CMP_RETURN_DIRECT( - nm_utils_ip4_address_same_prefix_cmp(ra.network, rb.network, ra.plen)); + NM_CMP_RETURN_DIRECT(nm_ip4_addr_same_prefix_cmp(ra.network, rb.network, ra.plen)); break; } case NMP_OBJECT_TYPE_IP6_ROUTE: @@ -2197,7 +2217,7 @@ _dedup_multi_index_cmp(const NML3ConfigData *a, NM_CMP_DIRECT(ra.metric, rb.metric); NM_CMP_DIRECT(ra.plen, rb.plen); NM_CMP_RETURN_DIRECT( - nm_utils_ip6_address_same_prefix_cmp(&ra.network, &rb.network, ra.plen)); + nm_ip6_addr_same_prefix_cmp(&ra.network, &rb.network, ra.plen)); break; } default: @@ -2274,7 +2294,6 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, } for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { - const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; const NMPObject *def_route_a = a->best_default_route_x[IS_IPv4]; const NMPObject *def_route_b = b->best_default_route_x[IS_IPv4]; @@ -2298,8 +2317,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_DIRECT(ra.metric, rb.metric); NM_CMP_DIRECT(ra.plen, rb.plen); - NM_CMP_RETURN_DIRECT( - nm_utils_ip4_address_same_prefix_cmp(ra.network, rb.network, ra.plen)); + NM_CMP_RETURN_DIRECT(nm_ip4_addr_same_prefix_cmp(ra.network, rb.network, ra.plen)); } else { NMPlatformIP6Route ra = def_route_a->ip6_route; NMPlatformIP6Route rb = def_route_b->ip6_route; @@ -2307,16 +2325,15 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_DIRECT(ra.metric, rb.metric); NM_CMP_DIRECT(ra.plen, rb.plen); NM_CMP_RETURN_DIRECT( - nm_utils_ip6_address_same_prefix_cmp(&ra.network, &rb.network, ra.plen)); + nm_ip6_addr_same_prefix_cmp(&ra.network, &rb.network, ra.plen)); } } if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_DNS)) { const NML3ConfigDatFlags FLAG = NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY(IS_IPv4); - NM_CMP_RETURN(_garray_inaddr_cmp(a->nameservers_x[IS_IPv4], - b->nameservers_x[IS_IPv4], - addr_family)); + NM_CMP_RETURN( + nm_strv_ptrarray_cmp(a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4])); NM_CMP_RETURN(nm_strv_ptrarray_cmp(a->domains_x[IS_IPv4], b->domains_x[IS_IPv4])); NM_CMP_RETURN(nm_strv_ptrarray_cmp(a->searches_x[IS_IPv4], b->searches_x[IS_IPv4])); NM_CMP_RETURN( @@ -2391,10 +2408,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, /*****************************************************************************/ static const NMPObject * -_data_get_direct_route_for_host(const NML3ConfigData *self, - int addr_family, - gconstpointer host, - guint32 route_table) +_data_get_direct_route_for_host(const NML3ConfigData *self, int addr_family, gconstpointer host) { const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMPObject *best_route_obj = NULL; @@ -2422,13 +2436,7 @@ _data_get_direct_route_for_host(const NML3ConfigData *self, if (best_route && best_route->rx.plen > item->rx.plen) continue; - if (nm_platform_route_table_uncoerce(item->rx.table_coerced, TRUE) != route_table) - continue; - - if (!nm_utils_ip_address_same_prefix(addr_family, - host, - item->rx.network_ptr, - item->rx.plen)) + if (!nm_ip_addr_same_prefix(addr_family, host, item->rx.network_ptr, item->rx.plen)) continue; if (best_route && best_route->rx.metric <= item->rx.metric) @@ -2478,9 +2486,9 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea if (my_addr->plen == 0) continue; - network_4 = nm_utils_ip4_address_clear_host_address(my_addr->peer_address, my_addr->plen); + network_4 = nm_ip4_addr_clear_host_address(my_addr->peer_address, my_addr->plen); - if (nm_utils_ip4_address_is_zeronet(network_4)) { + if (nm_ip4_addr_is_zeronet(network_4)) { /* Kernel doesn't add device-routes for destinations that * start with 0.x.y.z. Skip them. */ continue; @@ -2555,12 +2563,10 @@ nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_fam if (nm_ip_addr_is_null(addr_family, p_gateway)) continue; - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route_src) - || _data_get_direct_route_for_host( - self, - addr_family, - p_gateway, - nm_platform_route_table_uncoerce(route_src->rx.table_coerced, TRUE))) + if (NM_FLAGS_HAS(route_src->rx.r_rtm_flags, (unsigned) RTNH_F_ONLINK)) + continue; + + if (_data_get_direct_route_for_host(self, addr_family, p_gateway)) continue; new_route = nmp_object_clone(obj_src, FALSE); @@ -2672,9 +2678,9 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self, a6 = &addr_src->a6.peer_address; plen = 128; } else { - a6 = nm_utils_ip6_address_clear_host_address(&a6_stack, - &addr_src->a6.address, - addr_src->a6.plen); + a6 = nm_ip6_addr_clear_host_address(&a6_stack, + &addr_src->a6.address, + addr_src->a6.plen); plen = addr_src->a6.plen; } @@ -2819,12 +2825,12 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co plen = nm_ip_route_get_prefix(s_route); - nm_utils_ipx_address_clear_host_address(addr_family, &network_bin, &network_bin, plen); + nm_ip_addr_clear_host_address(addr_family, &network_bin, &network_bin, plen); if (IS_IPv4) { r.r4 = (NMPlatformIP4Route){ .network = network_bin.addr4, - .plen = nm_ip_route_get_prefix(s_route), + .plen = plen, .gateway = next_hop_bin.addr4, .metric_any = metric_any, .metric = metric, @@ -2834,7 +2840,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co } else { r.r6 = (NMPlatformIP6Route){ .network = network_bin.addr6, - .plen = nm_ip_route_get_prefix(s_route), + .plen = plen, .gateway = next_hop_bin.addr6, .metric_any = metric_any, .metric = metric, @@ -2845,19 +2851,28 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co nm_utils_ip_route_attribute_to_platform(addr_family, s_route, &r.rx, -1); + if (IS_IPv4 && r.r4.gateway == 0) { + /* As far as kernel is concerned, an IPv4 without gateway cannot have + * the onlink flag set, we need to clear it. If we wouldn't clear it, + * then the address we would add in kernel would be entirely different than + * the one we create here (because the "onlink" flag is part of the + * identifier of a route, see nm_platform_ip4_route_cmp()). + * + * Note however that for ECMP routes we currently can only merge routes + * that agree in their onlink flag. So a route without gateway cannot + * merge with an onlink route that has a gateway. That needs fixing, + * by not treating the onlink flag as for the entire route, but allowing + * to merge ECMP routes with different onlink flag. And first, we need + * to track the onlink flag for the nexthop (NMPlatformIP4RtNextHop). */ + r.r4.r_rtm_flags &= ~((unsigned) RTNH_F_ONLINK); + } + nm_l3_config_data_add_route(self, addr_family, NULL, &r.rx); } nnameservers = nm_setting_ip_config_get_num_dns(s_ip); - for (i = 0; i < nnameservers; i++) { - const char *s; - NMIPAddr ip; - - s = nm_setting_ip_config_get_dns(s_ip, i); - if (!nm_utils_parse_inaddr_bin(addr_family, s, NULL, &ip)) - continue; - nm_l3_config_data_add_nameserver(self, addr_family, &ip); - } + for (i = 0; i < nnameservers; i++) + nm_l3_config_data_add_nameserver(self, addr_family, nm_setting_ip_config_get_dns(s_ip, i)); nsearches = nm_setting_ip_config_get_num_dns_searches(s_ip); for (i = 0; i < nsearches; i++) { @@ -3023,6 +3038,107 @@ nm_l3_config_data_new_from_platform(NMDedupMultiIndex *multi_idx, /*****************************************************************************/ void +nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, + GChecksum *sum, + int addr_family, + NMDnsIPConfigType dns_ip_config_type) +{ + guint i; + int val; + const char *const *strarr; + const in_addr_t *wins; + const char *const *domains; + const char *const *searches; + const char *const *options; + guint num_nameservers; + guint num_wins; + guint num_domains; + guint num_searches; + guint num_options; + gboolean empty = TRUE; + + g_return_if_fail(l3cd); + g_return_if_fail(sum); + + strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers); + for (i = 0; i < num_nameservers; i++) { + g_checksum_update(sum, (gpointer) strarr[i], strlen(strarr[i])); + empty = FALSE; + } + + if (addr_family == AF_INET) { + wins = nm_l3_config_data_get_wins(l3cd, &num_wins); + for (i = 0; i < num_wins; i++) { + g_checksum_update(sum, (guint8 *) &wins[i], 4); + empty = FALSE; + } + } + + domains = nm_l3_config_data_get_domains(l3cd, addr_family, &num_domains); + for (i = 0; i < num_domains; i++) { + g_checksum_update(sum, (const guint8 *) domains[i], strlen(domains[i])); + empty = FALSE; + } + + searches = nm_l3_config_data_get_searches(l3cd, addr_family, &num_searches); + for (i = 0; i < num_searches; i++) { + g_checksum_update(sum, (const guint8 *) searches[i], strlen(searches[i])); + empty = FALSE; + } + + options = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num_options); + for (i = 0; i < num_options; i++) { + g_checksum_update(sum, (const guint8 *) options[i], strlen(options[i])); + empty = FALSE; + } + + val = nm_l3_config_data_get_mdns(l3cd); + if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT) { + g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); + empty = FALSE; + } + + val = nm_l3_config_data_get_llmnr(l3cd); + if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT) { + g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); + empty = FALSE; + } + + val = nm_l3_config_data_get_dns_over_tls(l3cd); + if (val != NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT) { + g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); + empty = FALSE; + } + + if (!empty) { + int prio = 0; + + /* In the DNS manager we rely on the fact that an empty (i.e. without + * any name server, domain, option, etc. parameters) configuration + * has a zero checksum. This is needed to avoid rewriting resolv.conf + * when not needed. Since the dns-type and the priority are always + * present, hash them only when the rest of configuration is not empty. + */ + g_checksum_update(sum, (const guint8 *) &dns_ip_config_type, sizeof(dns_ip_config_type)); + nm_l3_config_data_get_dns_priority(l3cd, addr_family, &prio); + g_checksum_update(sum, (const guint8 *) &prio, sizeof(prio)); + } + + /* FIXME(ip-config-checksum): the DNS priority should be considered relevant + * and added into the checksum as well, but this can't be done right now + * because in the DNS manager we rely on the fact that an empty + * configuration (i.e. just created) has a zero checksum. This is needed to + * avoid rewriting resolv.conf when there is no change. + * + * The DNS priority initial value depends on the connection type (VPN or + * not), so it's a bit difficult to add it to checksum maintaining the + * assumption of checksum(empty)=0 + */ +} + +/*****************************************************************************/ + +void nm_l3_config_data_merge(NML3ConfigData *self, const NML3ConfigData *src, NML3ConfigMergeFlags merge_flags, @@ -3212,9 +3328,7 @@ nm_l3_config_data_merge(NML3ConfigData *self, } if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) - _garray_inaddr_merge(&self->nameservers_x[IS_IPv4], - src->nameservers_x[IS_IPv4], - addr_family); + _strv_ptrarray_merge(&self->nameservers_x[IS_IPv4], src->nameservers_x[IS_IPv4]); if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) _strv_ptrarray_merge(&self->domains_x[IS_IPv4], src->domains_x[IS_IPv4]); diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index ca42d4a1..bfab04d9 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -495,12 +495,16 @@ const in_addr_t *nm_l3_config_data_get_wins(const NML3ConfigData *self, guint *o gboolean nm_l3_config_data_add_wins(NML3ConfigData *self, in_addr_t wins); -gconstpointer +const char *const * nm_l3_config_data_get_nameservers(const NML3ConfigData *self, int addr_family, guint *out_len); -gboolean nm_l3_config_data_add_nameserver(NML3ConfigData *self, - int addr_family, - gconstpointer /* (const NMIPAddr *) */ nameserver); +gboolean +nm_l3_config_data_add_nameserver(NML3ConfigData *self, int addr_family, const char *nameserver); + +gboolean nm_l3_config_data_add_nameserver_detail(NML3ConfigData *self, + int addr_family, + gconstpointer addr_bin, + const char *server_name); gboolean nm_l3_config_data_clear_nameservers(NML3ConfigData *self, int addr_family); @@ -600,4 +604,9 @@ nmtst_l3_config_data_get_best_gateway(const NML3ConfigData *self, int addr_famil return nm_platform_ip_route_get_gateway(addr_family, NMP_OBJECT_CAST_IP_ROUTE(rt)); } +void nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, + GChecksum *sum, + int addr_family, + NMDnsIPConfigType dns_ip_config_type); + #endif /* __NM_L3_CONFIG_DATA_H__ */ diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index 3fc1e165..ec871bef 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -104,17 +104,17 @@ NM_UTILS_ENUM2STR_DEFINE(nm_l3_ipv4ll_state_to_string, /*****************************************************************************/ -#define _ASSERT(self) \ - G_STMT_START \ - { \ - NML3IPv4LL *const _self = (self); \ - \ - nm_assert(NM_IS_L3_IPV4LL(_self)); \ - if (NM_MORE_ASSERTS > 5) { \ - nm_assert(_self->addr == 0u || nm_utils_ip4_address_is_link_local(_self->addr)); \ - nm_assert(!_self->l3cd || NM_IS_L3_CONFIG_DATA(_self->l3cd)); \ - } \ - } \ +#define _ASSERT(self) \ + G_STMT_START \ + { \ + NML3IPv4LL *const _self = (self); \ + \ + nm_assert(NM_IS_L3_IPV4LL(_self)); \ + if (NM_MORE_ASSERTS > 5) { \ + nm_assert(_self->addr == 0u || nm_ip4_addr_is_link_local(_self->addr)); \ + nm_assert(!_self->l3cd || NM_IS_L3_CONFIG_DATA(_self->l3cd)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ @@ -290,7 +290,7 @@ _ip4_address_is_link_local(const NMPlatformIP4Address *a) { nm_assert(a); - return nm_utils_ip4_address_is_link_local(a->address) && a->plen == ADDR_IPV4LL_PREFIX_LEN + return nm_ip4_addr_is_link_local(a->address) && a->plen == ADDR_IPV4LL_PREFIX_LEN && a->address == a->peer_address; } @@ -322,7 +322,7 @@ _l3cd_config_create(int ifindex, in_addr_t addr, NMDedupMultiIndex *multi_idx) { nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; - nm_assert(nm_utils_ip4_address_is_link_local(addr)); + nm_assert(nm_ip4_addr_is_link_local(addr)); nm_assert(ifindex > 0); nm_assert(multi_idx); @@ -382,7 +382,7 @@ static void _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) { CSipHash state; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; gboolean seed_changed = FALSE; in_addr_t addr_new; guint64 h; @@ -459,7 +459,7 @@ _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) if (!seed_changed && !generate_new_addr) { /* neither did the caller request a new address, nor was the seed changed. The current * address is still to be used. */ - nm_assert(nm_utils_ip4_address_is_link_local(self->addr)); + nm_assert(nm_ip4_addr_is_link_local(self->addr)); return; } @@ -492,9 +492,9 @@ gen_addr: if (self->addr == addr_new || NM_IN_SET(ntohl(addr_new) & 0x0000FF00u, 0x0000u, 0xFF00u)) goto gen_addr; - nm_assert(nm_utils_ip4_address_is_link_local(addr_new)); + nm_assert(nm_ip4_addr_is_link_local(addr_new)); - _LOGT("addr-gen: set address %s", _nm_utils_inet4_ntop(addr_new, sbuf_addr)); + _LOGT("addr-gen: set address %s", nm_inet4_ntop(addr_new, sbuf_addr)); self->addr = addr_new; } @@ -549,7 +549,7 @@ static void _l3cd_config_add(NML3IPv4LL *self) { nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; gboolean changed; _ASSERT(self); @@ -571,7 +571,7 @@ _l3cd_config_add(NML3IPv4LL *self) self->l3cd_timeout_msec_changed = FALSE; _LOGT("add l3cd config with %s (acd-timeout %u msec%s)", - _nm_utils_inet4_ntop(self->addr, sbuf_addr), + nm_inet4_ntop(self->addr, sbuf_addr), self->reg_timeout_msec, changed ? "" : " changed"); @@ -639,7 +639,7 @@ _ipv4ll_platform_ip4_address_lookup(NML3IPv4LL *self, in_addr_t addr) if (addr == 0u) return NULL; - nm_assert(nm_utils_ip4_address_is_link_local(addr)); + nm_assert(nm_ip4_addr_is_link_local(addr)); pladdr = nm_platform_ip4_address_get(nm_l3_ipv4ll_get_platform(self), nm_l3_ipv4ll_get_ifindex(self), @@ -658,7 +658,7 @@ _ipv4ll_l3cfg_get_acd_addr_info(NML3IPv4LL *self, in_addr_t addr) if (addr == 0u) return NULL; - nm_assert(nm_utils_ip4_address_is_link_local(addr)); + nm_assert(nm_ip4_addr_is_link_local(addr)); return nm_l3cfg_get_acd_addr_info(self->l3cfg, addr); } @@ -766,7 +766,7 @@ _ipv4ll_set_timed_out_update(NML3IPv4LL *self, TimedOutState new_state) static gboolean _ipv4ll_set_state(NML3IPv4LL *self, NML3IPv4LLState state) { - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; char sbuf100[100]; if (self->state == state) @@ -775,7 +775,7 @@ _ipv4ll_set_state(NML3IPv4LL *self, NML3IPv4LLState state) self->notify_on_idle = TRUE; _LOGT("state: set state %s (addr=%s)", nm_l3_ipv4ll_state_to_string(state, sbuf100, sizeof(sbuf100)), - _nm_utils_inet4_ntop(self->addr, sbuf_addr)); + nm_inet4_ntop(self->addr, sbuf_addr)); return TRUE; } diff --git a/src/core/nm-l3-ipv4ll.h b/src/core/nm-l3-ipv4ll.h index b39762a8..af74ce08 100644 --- a/src/core/nm-l3-ipv4ll.h +++ b/src/core/nm-l3-ipv4ll.h @@ -45,7 +45,7 @@ NM_IS_L3_IPV4LL(const NML3IPv4LL *self) { nm_assert(!self || (NM_IS_L3CFG(*((NML3Cfg **) self)) - && (*((int *) (((char *) self) + sizeof(gpointer)))) > 0)); + && *(NM_CAST_ALIGN(int, (((char *) self) + sizeof(gpointer)))) > 0)); return !!self; } diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c index 2640c075..2e2a6a0a 100644 --- a/src/core/nm-l3-ipv6ll.c +++ b/src/core/nm-l3-ipv6ll.c @@ -4,7 +4,7 @@ #include "nm-l3-ipv6ll.h" -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include "nm-core-utils.h" @@ -216,7 +216,7 @@ _emit_changed_on_idle_cb(gpointer user_data) _LOGT("emit changed signal (state=%s%s%s)", nm_l3_ipv6ll_state_to_string(state), lladdr ? ", " : "", - lladdr ? _nm_utils_inet6_ntop(lladdr, sbuf) : ""); + lladdr ? nm_inet6_ntop(lladdr, sbuf) : ""); self->notify_fcn(self, state, lladdr, self->user_data); @@ -525,14 +525,14 @@ _check(NML3IPv6LL *self) if (_pladdr_is_ll_tentative(pladdr)) { if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, pladdr)) { _LOGT("changed: waiting for address %s to complete DAD", - _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); + nm_inet6_ntop(&self->cur_lladdr, sbuf)); _lladdr_handle_changed(self); } return; } if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_READY, pladdr)) { - _LOGT("changed: address %s is ready", _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); + _LOGT("changed: address %s is ready", nm_inet6_ntop(&self->cur_lladdr, sbuf)); _lladdr_handle_changed(self); } return; @@ -545,9 +545,9 @@ _check(NML3IPv6LL *self) NM_IN_SET(self->state, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, NM_L3_IPV6LL_STATE_READY)); if (self->state == NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS) _LOGT("changed: address %s did not complete DAD", - _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); + nm_inet6_ntop(&self->cur_lladdr, sbuf)); else { - _LOGT("changed: address %s is gone", _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); + _LOGT("changed: address %s is gone", nm_inet6_ntop(&self->cur_lladdr, sbuf)); } /* reset the state here, so that we are sure that the following @@ -579,8 +579,7 @@ _check(NML3IPv6LL *self) * If that does not happen within timeout, we assume that this address failed DAD. */ self->wait_for_addr_source = nm_g_timeout_add_source(2000, _wait_for_addr_timeout_cb, self); if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, &lladdr)) { - _LOGT("changed: starting DAD for address %s", - _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); + _LOGT("changed: starting DAD for address %s", nm_inet6_ntop(&self->cur_lladdr, sbuf)); _lladdr_handle_changed(self); } return; diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 8fa1e07d..a49654fe 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -7,7 +7,7 @@ #include "libnm-std-aux/nm-linux-compat.h" #include <net/if.h> -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include <linux/if_ether.h> #include <linux/rtnetlink.h> @@ -358,16 +358,16 @@ G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) } \ G_STMT_END -#define _LOGT_acd(acd_data, ...) \ - G_STMT_START \ - { \ - char _sbuf_acd[NM_UTILS_INET_ADDRSTRLEN]; \ - \ - _LOGT("acd[%s, %s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _nm_utils_inet4_ntop((acd_data)->info.addr, _sbuf_acd), \ - _l3_acd_addr_state_to_string((acd_data)->info.state) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ +#define _LOGT_acd(acd_data, ...) \ + G_STMT_START \ + { \ + char _sbuf_acd[NM_INET_ADDRSTRLEN]; \ + \ + _LOGT("acd[%s, %s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + nm_inet4_ntop((acd_data)->info.addr, _sbuf_acd), \ + _l3_acd_addr_state_to_string((acd_data)->info.state) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ G_STMT_END /*****************************************************************************/ @@ -548,7 +548,7 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, char *sbuf, gsize sbuf_size) { - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; char sbuf100[100]; char sbufobf[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE]; char *s = sbuf; @@ -577,7 +577,7 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, nm_strbuf_append(&s, &l, ", addr=%s, state=%s", - _nm_utils_inet4_ntop(notify_data->acd_event.info.addr, sbuf_addr), + nm_inet4_ntop(notify_data->acd_event.info.addr, sbuf_addr), _l3_acd_addr_state_to_string(notify_data->acd_event.info.state)); break; case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE: @@ -603,7 +603,7 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, &l, ", ipv4ll=" NM_HASH_OBFUSCATE_PTR_FMT "%s%s, state=%s", NM_HASH_OBFUSCATE_PTR(notify_data->ipv4ll_event.ipv4ll), - NM_PRINT_FMT_QUOTED2(addr4 != 0, ", addr=", _nm_utils_inet4_ntop(addr4, sbuf_addr), ""), + NM_PRINT_FMT_QUOTED2(addr4 != 0, ", addr=", nm_inet4_ntop(addr4, sbuf_addr), ""), nm_l3_ipv4ll_state_to_string(nm_l3_ipv4ll_get_state(notify_data->ipv4ll_event.ipv4ll), sbuf100, sizeof(sbuf100))); @@ -1143,7 +1143,7 @@ _commit_collect_routes(NML3Cfg *self, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)); if (!head_entry) - return; + goto loop_done; c_list_for_each_entry (entry, &head_entry->lst_entries_head, lst_entries) { const NMPObject *obj = entry->obj; @@ -1152,6 +1152,14 @@ _commit_collect_routes(NML3Cfg *self, if (_obj_is_route_nodev(obj)) r = routes_nodev; else { + nm_assert(NMP_OBJECT_CAST_IP_ROUTE(obj)->ifindex == self->priv.ifindex); + + if (IS_IPv4 && NMP_OBJECT_CAST_IP4_ROUTE(obj)->weight > 0) { + /* This route needs to be registered as ECMP route. */ + nm_netns_ip_route_ecmp_register(self->priv.netns, self, obj); + continue; + } + if (!_obj_states_sync_filter(self, obj, commit_type)) continue; r = routes; @@ -1162,6 +1170,36 @@ _commit_collect_routes(NML3Cfg *self, g_ptr_array_add(*r, (gpointer) nmp_object_ref(obj)); } + +loop_done: + + if (IS_IPv4) { + gs_unref_ptrarray GPtrArray *singlehop_routes = NULL; + guint i; + + /* NMNetns will merge the routes. The ones that found a merge partner are true multihop + * routes, with potentially a next hop on different interfaces. The routes + * that didn't find a merge partner are returned in "singlehop_routes". */ + nm_netns_ip_route_ecmp_commit(self->priv.netns, + self, + &singlehop_routes, + NM_IN_SET(commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY)); + + if (singlehop_routes) { + for (i = 0; i < singlehop_routes->len; i++) { + const NMPObject *obj = singlehop_routes->pdata[i]; + + if (!_obj_states_sync_filter(self, obj, commit_type)) + continue; + + if (!*routes) + *routes = + g_ptr_array_new_with_free_func((GDestroyNotify) nm_dedup_multi_obj_unref); + + g_ptr_array_add(*routes, (gpointer) nmp_object_ref(obj)); + } + } + } } static void @@ -1430,7 +1468,8 @@ _acd_data_free(AcdData *acd_data) } static guint -_acd_data_collect_tracks_data(const AcdData *acd_data, +_acd_data_collect_tracks_data(NML3Cfg *self, + const AcdData *acd_data, NMTernary dirty_selector, guint32 *out_best_acd_timeout_msec, NML3AcdDefendType *out_best_acd_defend_type) @@ -1466,6 +1505,12 @@ _acd_data_collect_tracks_data(const AcdData *acd_data, nm_assert(n == 0 || best_acd_defend_type > _NM_L3_ACD_DEFEND_TYPE_NONE); nm_assert(best_acd_defend_type <= NM_L3_ACD_DEFEND_TYPE_ALWAYS); + if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) { + /* On loopback interface, ACD makes no sense. We always force the + * timeout to zero, which means no ACD. */ + best_acd_timeout_msec = 0; + } + NM_SET_OUT(out_best_acd_timeout_msec, n > 0 ? best_acd_timeout_msec : 0u); NM_SET_OUT(out_best_acd_defend_type, best_acd_defend_type); return n; @@ -2230,7 +2275,7 @@ _l3_acd_data_state_change(NML3Cfg *self, gint64 now_msec; const char *log_reason; char sbuf256[256]; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; if (!p_now_msec) { now_msec = 0; @@ -2313,7 +2358,8 @@ _l3_acd_data_state_change(NML3Cfg *self, return; handle_init: - if (_acd_data_collect_tracks_data(acd_data, + if (_acd_data_collect_tracks_data(self, + acd_data, NM_TERNARY_FALSE, &acd_timeout_msec, &acd_defend_type) @@ -2362,7 +2408,8 @@ handle_init: /* we just did a commit of the IP configuration and now visit all ACD states * and kick off the necessary actions... */ - if (_acd_data_collect_tracks_data(acd_data, + if (_acd_data_collect_tracks_data(self, + acd_data, NM_TERNARY_TRUE, &acd_timeout_msec, &acd_defend_type) @@ -2465,7 +2512,8 @@ handle_init: /* after a timeout, re-probe the address. This only happens if the caller * does not deconfigure the address after USED/CONFLICT. But in that case, * we eventually want to retry. */ - if (_acd_data_collect_tracks_data(acd_data, + if (_acd_data_collect_tracks_data(self, + acd_data, NM_TERNARY_TRUE, &acd_timeout_msec, &acd_defend_type) @@ -2550,7 +2598,7 @@ handle_init: if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) { _LOGI("IPv4 address %s is used on network connected to interface %d%s%s%s from " "host %s", - _nm_utils_inet4_ntop(acd_data->info.addr, sbuf_addr), + nm_inet4_ntop(acd_data->info.addr, sbuf_addr), self->priv.ifindex, NM_PRINT_FMT_QUOTED(self->priv.plobj_next, " (", @@ -2565,7 +2613,7 @@ handle_init: nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_DEFENDING); _LOGT_acd(acd_data, "address %s defended from %s", - _nm_utils_inet4_ntop(acd_data->info.addr, sbuf_addr), + nm_inet4_ntop(acd_data->info.addr, sbuf_addr), nm_ether_addr_to_string_a(sender_addr)); /* we just log an info message. Nothing else to do. */ return; @@ -2575,7 +2623,7 @@ handle_init: _LOGT_acd(acd_data, "address conflict for %s detected with %s", - _nm_utils_inet4_ntop(acd_data->info.addr, sbuf_addr), + nm_inet4_ntop(acd_data->info.addr, sbuf_addr), nm_ether_addr_to_string_a(sender_addr)); if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) { @@ -2587,7 +2635,7 @@ handle_init: NMP_OBJECT_CAST_LINK(self->priv.plobj_next)->name, ")", ""), - _nm_utils_inet4_ntop(acd_data->info.addr, sbuf_addr), + nm_inet4_ntop(acd_data->info.addr, sbuf_addr), nm_ether_addr_to_string_a(sender_addr)); } @@ -2990,68 +3038,103 @@ nm_l3cfg_check_ready(NML3Cfg *self, const NML3ConfigData *l3cd, int addr_family, NML3CfgCheckReadyFlags flags, - gboolean *acd_used) + GArray **conflicts) { NMDedupMultiIter iter; const NMPObject *obj; + gboolean ready = TRUE; nm_assert(NM_IS_L3CFG(self)); - nm_assert_addr_family_or_unspec(addr_family); - - NM_SET_OUT(acd_used, FALSE); + nm_assert_addr_family(addr_family); + nm_assert(!conflicts || !*conflicts); if (!l3cd) return TRUE; - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET) - && NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY)) { - gboolean pending = FALSE; - - nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) { - const NML3AcdAddrInfo *addr_info; - - addr_info = nm_l3cfg_get_acd_addr_info(self, NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address); - if (!addr_info) { - /* We don't track the this address? That's odd. Not ready. */ - pending = TRUE; - } else { - if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) { - /* Still probing. Not ready. */ - pending = TRUE; - } else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) { - NM_SET_OUT(acd_used, TRUE); + if (addr_family == AF_INET) { + if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY)) { + nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) { + const NML3AcdAddrInfo *addr_info; + + addr_info = + nm_l3cfg_get_acd_addr_info(self, NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address); + if (!addr_info) { + /* We don't track the this address? That's odd. Not ready. */ + ready = FALSE; + } else { + if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) { + /* Still probing. Not ready. */ + ready = FALSE; + } else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) { + if (conflicts) { + if (!*conflicts) + *conflicts = g_array_new(FALSE, + FALSE, + nm_utils_addr_family_to_size(addr_family)); + g_array_append_val(*conflicts, addr_info->addr); + } + } } + /* we only care that we don't have ACD still pending. Otherwise we are ready, + * including if we have no addr_info about this address or the address is in use. */ } - /* we only care that we don't have ACD still pending. Otherwise we are ready, - * including if we have no addr_info about this address or the address is in use. */ } - if (pending) - return FALSE; + return ready; } - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6) - && NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) { + /* AF_INET6 */ + if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) { nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { ObjStateData *obj_state; + gboolean dadfailed = FALSE; obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); if (!obj_state) { /* Hm, we don't track this object? That is odd. Not ready. */ - return FALSE; + ready = FALSE; + continue; } if (!obj_state->os_nm_configured && !obj_state->os_plobj) { /* We didn't (yet) configure this address and it also is not in platform. * Not ready. */ - return FALSE; + ready = FALSE; + continue; + } + + if (obj_state->os_plobj + && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags, + IFA_F_DADFAILED)) { + /* The address is still present with DADFAILED flag. */ + dadfailed = TRUE; + } else if (obj_state->os_nm_configured && !obj_state->os_plobj + && nm_platform_ip6_dadfailed_check( + self->priv.platform, + self->priv.ifindex, + &NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address)) { + /* We configured the address and kernel removed it with DADFAILED flag. */ + dadfailed = TRUE; + } + + if (dadfailed) { + if (conflicts) { + if (!*conflicts) { + *conflicts = + g_array_new(FALSE, FALSE, nm_utils_addr_family_to_size(addr_family)); + } + g_array_append_val(*conflicts, + NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address); + } + continue; } if (obj_state->os_plobj && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags, IFA_F_TENTATIVE)) { /* The address is configured in kernel, but still tentative. Not ready. */ - return FALSE; + ready = FALSE; + continue; } /* This address is ready. Even if it is not (not anymore) configured in kernel (as @@ -3060,7 +3143,7 @@ nm_l3cfg_check_ready(NML3Cfg *self, } } - return TRUE; + return ready; } /*****************************************************************************/ @@ -3144,7 +3227,7 @@ nm_l3cfg_commit_on_idle_is_scheduled(NML3Cfg *self) /*****************************************************************************/ #define _l3_config_datas_at(l3_config_datas, idx) \ - (&g_array_index((l3_config_datas), L3ConfigData, (idx))) + (&nm_g_array_index((l3_config_datas), L3ConfigData, (idx))) static gssize _l3_config_datas_find_next(GArray *l3_config_datas, @@ -3395,8 +3478,10 @@ nm_l3cfg_add_config(NML3Cfg *self, nm_assert(l3_config_data->acd_defend_type_confdata == acd_defend_type); - if (changed) + if (changed) { _l3_changed_configs_set_dirty(self); + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); + } return changed; } @@ -3440,6 +3525,9 @@ _l3cfg_remove_config(NML3Cfg *self, } } + if (changed) + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); + if (self->priv.p->l3_config_datas->len == 0) { nm_assert(changed); nm_clear_pointer(&self->priv.p->l3_config_datas, g_array_unref); @@ -3713,6 +3801,38 @@ _l3cfg_update_combined_config(NML3Cfg *self, &hook_data); } + if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) { + NMPlatformIPXAddress ax; + NMPlatformIPXRoute rx; + + if (!nm_l3_config_data_lookup_address_4(l3cd, + NM_IPV4LO_ADDR1, + NM_IPV4LO_PREFIXLEN, + NM_IPV4LO_ADDR1)) { + nm_l3_config_data_add_address_4( + l3cd, + nm_platform_ip4_address_init_loopback_addr1(&ax.a4)); + } + if (!nm_l3_config_data_lookup_address_6(l3cd, &in6addr_loopback)) { + nm_l3_config_data_add_address_6(l3cd, + nm_platform_ip6_address_init_loopback(&ax.a6)); + } + + rx.r4 = (NMPlatformIP4Route){ + .ifindex = NM_LOOPBACK_IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, + .network = NM_IPV4LO_ADDR1, + .plen = NM_IPV4LO_PREFIXLEN, + .table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL), + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .pref_src = NM_IPV4LO_ADDR1, + }; + nm_platform_ip_route_normalize(AF_INET, &rx.rx); + if (!nm_l3_config_data_lookup_route(l3cd, AF_INET, &rx.rx)) { + nm_l3_config_data_add_route_4(l3cd, &rx.r4); + } + } for (i = 0; i < l3_config_datas_len; i++) { const L3ConfigData *l3cd_data = l3_config_datas_arr[i]; int IS_IPv4; @@ -4371,9 +4491,9 @@ _l3_commit_mptcp_af(NML3Cfg *self, default: if (IS_IPv4) { /* We take all addresses, including rfc1918 private addresses - * (nm_utils_ip_is_site_local()). */ + * (nm_ip_addr_is_site_local()). */ } else { - if (nm_utils_ip6_is_ula(&addr->a6.address)) { + if (nm_ip6_addr_is_ula(&addr->a6.address)) { /* Exclude unique local IPv6 addresses fc00::/7. */ goto skip_addr; } else { @@ -4470,7 +4590,7 @@ _l3_commit_one(NML3Cfg *self, gs_unref_ptrarray GPtrArray *addresses_prune = NULL; gs_unref_ptrarray GPtrArray *routes_prune = NULL; gs_unref_ptrarray GPtrArray *routes_temporary_not_available_arr = NULL; - NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE; + NMIPRouteTableSyncMode route_table_sync; gboolean final_failure_for_temporary_not_available = FALSE; char sbuf_commit_type[50]; gboolean success = TRUE; @@ -4487,15 +4607,15 @@ _l3_commit_one(NML3Cfg *self, nm_utils_addr_family_to_char(addr_family), _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); - if (self->priv.p->combined_l3cd_commited) { - addresses = _commit_collect_addresses(self, addr_family, commit_type); + addresses = _commit_collect_addresses(self, addr_family, commit_type); - _commit_collect_routes(self, addr_family, commit_type, &routes, &routes_nodev); + _commit_collect_routes(self, addr_family, commit_type, &routes, &routes_nodev); - route_table_sync = - nm_l3_config_data_get_route_table_sync(self->priv.p->combined_l3cd_commited, - addr_family); - } + route_table_sync = + self->priv.p->combined_l3cd_commited + ? nm_l3_config_data_get_route_table_sync(self->priv.p->combined_l3cd_commited, + addr_family) + : NM_IP_ROUTE_TABLE_SYNC_MODE_NONE; if (!IS_IPv4) { _l3_commit_ip6_privacy(self, commit_type); @@ -4552,6 +4672,23 @@ _l3_commit_one(NML3Cfg *self, } } + if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) { + if (!addresses) { + NMPlatformIPXAddress ax; + + addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + if (IS_IPv4) { + g_ptr_array_add( + addresses, + nmp_object_new(NMP_OBJECT_TYPE_IP4_ADDRESS, + nm_platform_ip4_address_init_loopback_addr1(&ax.a4))); + } else { + g_ptr_array_add(addresses, + nmp_object_new(NMP_OBJECT_TYPE_IP6_ADDRESS, + nm_platform_ip6_address_init_loopback(&ax.a6))); + } + } + } /* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ndisc_*(). */ /* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_mtu(). */ @@ -4559,7 +4696,10 @@ _l3_commit_one(NML3Cfg *self, addr_family, self->priv.ifindex, addresses, - addresses_prune); + addresses_prune, + self->priv.ifindex == NM_LOOPBACK_IFINDEX + ? NMP_IP_ADDRESS_SYNC_FLAGS_NONE + : NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE); _nodev_routes_sync(self, addr_family, commit_type, routes_nodev); @@ -4810,6 +4950,9 @@ nm_l3cfg_commit_type_register(NML3Cfg *self, c_list_link_tail(&self->priv.p->commit_type_lst_head, &handle->commit_type_lst); ret = handle; + + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); + out: _LOGT("commit type register (type \"%s\", source \"%s\", existing " NM_HASH_OBFUSCATE_PTR_FMT ") -> " NM_HASH_OBFUSCATE_PTR_FMT "", @@ -4832,6 +4975,8 @@ nm_l3cfg_commit_type_unregister(NML3Cfg *self, NML3CfgCommitTypeHandle *handle) _LOGT("commit type unregister " NM_HASH_OBFUSCATE_PTR_FMT "", NM_HASH_OBFUSCATE_PTR(handle)); + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); + c_list_unlink_stale(&handle->commit_type_lst); if (c_list_is_empty(&self->priv.p->commit_type_lst_head)) g_object_unref(self); @@ -5024,6 +5169,9 @@ nm_l3cfg_init(NML3Cfg *self) c_list_init(&self->priv.p->blocked_lst_head_4); c_list_init(&self->priv.p->blocked_lst_head_6); + c_list_init(&self->internal_netns.signal_pending_lst); + c_list_init(&self->internal_netns.ecmp_track_ifindex_lst_head); + self->priv.p->obj_state_hash = g_hash_table_new_full(nmp_object_indirect_id_hash, nmp_object_indirect_id_equal, _obj_state_data_free, @@ -5066,6 +5214,9 @@ finalize(GObject *object) NML3Cfg *self = NM_L3CFG(object); gboolean changed; + nm_assert(c_list_is_empty(&self->internal_netns.signal_pending_lst)); + nm_assert(c_list_is_empty(&self->internal_netns.ecmp_track_ifindex_lst_head)); + nm_assert(!self->priv.p->ipconfig_4); nm_assert(!self->priv.p->ipconfig_6); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index e0257623..9d622b4a 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -13,7 +13,7 @@ #define NM_ACD_TIMEOUT_MAX_MSEC 30000u #define NM_TYPE_L3CFG (nm_l3cfg_get_type()) -#define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg)) +#define NM_L3CFG(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg)) #define NM_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_L3CFG, NML3CfgClass)) #define NM_IS_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_L3CFG)) #define NM_IS_L3CFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_L3CFG)) @@ -209,6 +209,16 @@ struct _NML3Cfg { const NMPObject *plobj_next; int ifindex; } priv; + + /* NML3Cfg strongly cooperates with NMNetns. The latter is + * the one that creates and manages (also) the lifetime of the + * NML3Cfg instance. We track some per-l3cfg-data that is only + * relevant to NMNetns here. */ + struct { + guint32 signal_pending_obj_type_flags; + CList signal_pending_lst; + CList ecmp_track_ifindex_lst_head; + } internal_netns; }; typedef struct _NML3CfgClass NML3CfgClass; @@ -400,7 +410,7 @@ gboolean nm_l3cfg_check_ready(NML3Cfg *self, const NML3ConfigData *l3cd, int addr_family, NML3CfgCheckReadyFlags flags, - gboolean *acd_used); + GArray **conflicts); gboolean nm_l3cfg_has_temp_not_available_obj(NML3Cfg *self, int addr_family); diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 822df7ad..66547294 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -19,6 +19,7 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-factory.h" #include "devices/nm-device-generic.h" +#include "devices/nm-device-loopback.h" #include "devices/nm-device.h" #include "dns/nm-dns-manager.h" #include "dhcp/nm-dhcp-manager.h" @@ -114,6 +115,7 @@ static guint signals[LAST_SIGNAL] = {0}; NM_GOBJECT_PROPERTIES_DEFINE(NMManager, PROP_VERSION, + PROP_VERSION_INFO, PROP_CAPABILITIES, PROP_STATE, PROP_STARTUP, @@ -419,6 +421,31 @@ static NM_CACHED_QUARK_FCN("autoconnect-root", autoconnect_root_quark); /*****************************************************************************/ +static GVariant * +_version_info_get(void) +{ + const guint32 arr[] = { + NM_VERSION, + }; + + /* The array contains as first element NM_VERSION, which can be + * used to numerically compare the version (see also NM_ENCODE_VERSION, + * nm_utils_version(), nm_encode_version() and nm_decode_version(). + * + * The following elements of the array are a bitfield of capabilities. + * These capabilities should only depend on compile-time abilities + * (unlike NM_MANAGER_CAPABILITIES, NMCapability). The supported values + * are from NMVersionInfoCapability enum. This way to expose capabilities + * is more cumbersome but more efficient compared to NM_MANAGER_CAPABILITIES. + * As such, it is cheap to add capabilities for something, where you would + * avoid it as NM_MANAGER_CAPABILITIES due to the overhead. + */ + + return nm_g_variant_new_au(arr, G_N_ELEMENTS(arr)); +} + +/*****************************************************************************/ + static gboolean _connection_is_vpn(NMConnection *connection) { @@ -632,11 +659,8 @@ static guint _device_route_metric_data_by_ifindex_hash(gconstpointer p) { const DeviceRouteMetricData *data = p; - NMHashState h; - nm_hash_init(&h, 1030338191); - nm_hash_update_vals(&h, data->ifindex); - return nm_hash_complete(&h); + return nm_hash_val(1030338191, data->ifindex); } static gboolean @@ -1464,8 +1488,11 @@ find_best_device_state(NMManager *manager) NMActiveConnection *ac; c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { - NMActiveConnectionState ac_state = nm_active_connection_get_state(ac); + NMActiveConnectionState ac_state; + if (NM_IS_DEVICE_LOOPBACK(nm_active_connection_get_device(ac))) + continue; + ac_state = nm_active_connection_get_state(ac); switch (ac_state) { case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: if (nm_active_connection_get_default(ac, AF_UNSPEC)) { @@ -1890,8 +1917,11 @@ find_parent_device_for_connection(NMManager *self, * with some known device. */ c_list_for_each_entry (candidate, &priv->devices_lst_head, devices_lst) { - /* Unmanaged devices are not compatible with any connection */ - if (!nm_device_get_managed(candidate, FALSE)) + /* For a realized device, check that it's managed; otherwise it's not + * compatible with any connection. If the device is unrealized then + * the managed state is meaningless. + */ + if (nm_device_is_real(candidate) && !nm_device_get_managed(candidate, FALSE)) continue; if (nm_device_get_settings_connection(candidate) == parent_connection) @@ -1949,7 +1979,7 @@ nm_manager_get_connection_iface(NMManager *self, g_set_error(error, NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, + NM_MANAGER_ERROR_MISSING_PLUGIN, "NetworkManager plugin for '%s' unavailable", nm_connection_get_connection_type(connection)); return NULL; @@ -3083,12 +3113,11 @@ recheck_assume_connection(NMManager *self, NMDevice *device) g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); if (!nm_device_get_managed(device, FALSE)) { - /* If the device is unmanaged by NM_UNMANAGED_PLATFORM_INIT or NM_UNMANAGED_PARENT, + /* If the device is unmanaged by NM_UNMANAGED_PLATFORM_INIT, * don't reset the state now but wait until it becomes managed. */ - if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) - & ~(NM_UNMANAGED_PLATFORM_INIT | NM_UNMANAGED_PARENT)) + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) & ~NM_UNMANAGED_PLATFORM_INIT) nm_device_assume_state_reset(device); - _LOG2D(LOGD_DEVICE, device, "assume: don't assume because %s", "not managed"); + _LOG2D(LOGD_DEVICE, device, "assume: don't assume because device is not managed"); return FALSE; } @@ -3341,6 +3370,9 @@ _get_best_connectivity(NMManager *self, int addr_family) NMConnectivityState state; gint64 metric; + if (NM_IS_DEVICE_LOOPBACK(dev)) + continue; + r = nm_device_get_best_default_route(dev, addr_family); if (r) metric = NMP_OBJECT_CAST_IP_ROUTE(r)->metric; @@ -3410,10 +3442,9 @@ _device_realize_finish(NMManager *self, NMDevice *device, const NMPlatformLink * nm_device_realize_finish(device, plink); if (!nm_device_get_managed(device, FALSE)) { - /* If the device is unmanaged by NM_UNMANAGED_PLATFORM_INIT or NM_UNMANAGED_PARENT, + /* If the device is unmanaged by NM_UNMANAGED_PLATFORM_INIT, * don't reset the state now but wait until it becomes managed. */ - if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) - & ~(NM_UNMANAGED_PLATFORM_INIT | NM_UNMANAGED_PARENT)) + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) & ~NM_UNMANAGED_PLATFORM_INIT) nm_device_assume_state_reset(device); return; } @@ -4608,11 +4639,9 @@ ensure_master_active_connection(NMManager *self, NULL)) continue; - if (!nm_device_is_software(candidate)) { - master_state = nm_device_get_state(candidate); - if (nm_device_is_real(candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED) - continue; - } + if (nm_device_is_real(candidate) + && nm_device_get_state(candidate) != NM_DEVICE_STATE_DISCONNECTED) + continue; master_ac = nm_manager_activate_connection( self, @@ -4715,8 +4744,10 @@ find_slaves(NMManager *manager, } nm_assert(n_slaves < n_all_connections); - slaves[n_slaves].connection = candidate, slaves[n_slaves].device = slave_device, - n_slaves++; + slaves[n_slaves++] = (SlaveConnectionInfo){ + .connection = candidate, + .device = slave_device, + }; if (slave_device) g_hash_table_add(devices, slave_device); @@ -6612,7 +6643,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed) } /* Give the connections a chance to recreate the virtual devices. - * We've torn them down on sleep. */ + * We've torn them down on sleep. */ connections_changed(self); } @@ -7089,10 +7120,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde ifindex = nm_device_get_ip_ifindex(device); if (ifindex <= 0) return FALSE; - if (ifindex == 1) { - /* ignore loopback */ - return FALSE; - } if (!nm_platform_link_get(priv->platform, ifindex)) return FALSE; @@ -7904,12 +7931,12 @@ nm_manager_set_capability(NMManager *self, NMCapability cap) priv = NM_MANAGER_GET_PRIVATE(self); - idx = nm_utils_array_find_binary_search(&g_array_index(priv->capabilities, guint32, 0), - sizeof(guint32), - priv->capabilities->len, - &cap_i, - nm_cmp_uint32_p_with_data, - NULL); + idx = nm_array_find_bsearch(nm_g_array_first_p(priv->capabilities, guint32), + priv->capabilities->len, + sizeof(guint32), + &cap_i, + nm_cmp_uint32_p_with_data, + NULL); if (idx >= 0) return; @@ -8132,9 +8159,12 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_VERSION: g_value_set_string(value, VERSION); break; + case PROP_VERSION_INFO: + g_value_set_variant(value, _version_info_get()); + break; case PROP_CAPABILITIES: g_value_set_variant(value, - nm_g_variant_new_au((const guint32 *) priv->capabilities->data, + nm_g_variant_new_au(nm_g_array_first_p(priv->capabilities, guint32), priv->capabilities->len)); break; case PROP_STATE: @@ -8645,6 +8675,9 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = { NM_MANAGER_ACTIVATING_CONNECTION), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Startup", "b", NM_MANAGER_STARTUP), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Version", "s", NM_MANAGER_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VersionInfo", + "au", + NM_MANAGER_VERSION_INFO), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Capabilities", "au", NM_MANAGER_CAPABILITIES), @@ -8703,6 +8736,14 @@ nm_manager_class_init(NMManagerClass *manager_class) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_VERSION_INFO] = + g_param_spec_variant(NM_MANAGER_VERSION_INFO, + "", + "", + G_VARIANT_TYPE("au"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CAPABILITIES] = g_param_spec_variant(NM_MANAGER_CAPABILITIES, "", diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h index fcb00227..0cbbcbf0 100644 --- a/src/core/nm-manager.h +++ b/src/core/nm-manager.h @@ -12,7 +12,7 @@ #include "nm-dbus-manager.h" #define NM_TYPE_MANAGER (nm_manager_get_type()) -#define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MANAGER, NMManager)) +#define NM_MANAGER(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MANAGER, NMManager)) #define NM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MANAGER, NMManagerClass)) #define NM_IS_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MANAGER)) #define NM_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MANAGER)) @@ -20,6 +20,7 @@ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MANAGER, NMManagerClass)) #define NM_MANAGER_VERSION "version" +#define NM_MANAGER_VERSION_INFO "version-info" #define NM_MANAGER_CAPABILITIES "capabilities" #define NM_MANAGER_STATE "state" #define NM_MANAGER_STARTUP "startup" diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index 859dbb21..12ca8508 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -7,6 +7,8 @@ #include "nm-netns.h" +#include <linux/rtnetlink.h> + #include "libnm-glib-aux/nm-dedup-multi.h" #include "libnm-glib-aux/nm-c-list.h" @@ -16,6 +18,7 @@ #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" #include "libnm-platform/nmp-global-tracker.h" +#include "libnm-std-aux/c-list-util.h" /*****************************************************************************/ @@ -28,6 +31,8 @@ typedef struct { NMPGlobalTracker *global_tracker; GHashTable *l3cfgs; GHashTable *shared_ips; + GHashTable *ecmp_track_by_obj; + GHashTable *ecmp_track_by_ecmpid; CList l3cfg_signal_pending_lst_head; GSource *signal_pending_idle_source; } NMNetnsPrivate; @@ -67,6 +72,165 @@ NM_DEFINE_SINGLETON_GETTER(NMNetns, nm_netns_get, NM_TYPE_NETNS); /*****************************************************************************/ +#define nm_assert_l3cfg(self, l3cfg) \ + G_STMT_START \ + { \ + NMNetns *_self = (self); \ + NML3Cfg *_l3cfg = (l3cfg); \ + \ + nm_assert(NM_IS_NETNS(self)); \ + nm_assert(NM_IS_L3CFG(_l3cfg)); \ + if (NM_MORE_ASSERTS > 5) \ + nm_assert(_l3cfg == nm_netns_l3cfg_get(_self, nm_l3cfg_get_ifindex(_l3cfg))); \ + } \ + G_STMT_END + +/*****************************************************************************/ + +typedef struct { + const NMPObject *representative_obj; + const NMPObject *merged_obj; + CList ecmpid_lst_head; + bool needs_update : 1; + bool already_visited : 1; +} EcmpTrackEcmpid; + +typedef struct { + const NMPObject *obj; + + NML3Cfg *l3cfg; + EcmpTrackEcmpid *parent_track_ecmpid; + + CList ifindex_lst; + CList ecmpid_lst; + + /* Calling nm_netns_ip_route_ecmp_register() will ensure that the tracked + * entry is non-dirty. This can be used to remove stale entries. */ + bool dirty : 1; + + /* This flag is set during nm_netns_ip_route_ecmp_register(), when first tracking the + * route. It is cleared on the next nm_netns_ip_route_ecmp_commit(). It thus only + * exists for a short time, to know during a commit that the route is new and + * we need to do something special. */ + bool is_new : 1; + + /* The entry is ready to be configured. This exists, because the nexthop of + * a route must be reachable directly (being onlink). That is, we may need + * to add a direct, single-hop route to the gateway, which is done by + * the NML3Cfg of that interface. Since the NML3Cfg calls nm_netns_ip_route_ecmp_commit() + * and only adds the direct route afterwards, the ECMP route may not be ready + * right away, but only upon seeing the entry a second time. */ + bool is_ready : 1; +} EcmpTrackObj; + +static int +_ecmp_track_sort_lst_cmp(const CList *a, const CList *b, const void *user_data) +{ + EcmpTrackObj *track_obj_a = c_list_entry(a, EcmpTrackObj, ecmpid_lst); + EcmpTrackObj *track_obj_b = c_list_entry(b, EcmpTrackObj, ecmpid_lst); + const NMPlatformIP4Route *route_a = NMP_OBJECT_CAST_IP4_ROUTE(track_obj_a->obj); + const NMPlatformIP4Route *route_b = NMP_OBJECT_CAST_IP4_ROUTE(track_obj_b->obj); + + nm_assert(route_a->ifindex > 0); + nm_assert(route_a->n_nexthops <= 1); + nm_assert(route_b->ifindex > 0); + nm_assert(route_b->n_nexthops <= 1); + + NM_CMP_FIELD(route_a, route_b, ifindex); + NM_CMP_FIELD(route_b, route_a, weight); + NM_CMP_DIRECT(htonl(route_a->gateway), htonl(route_b->gateway)); + + return nm_assert_unreachable_val( + nm_platform_ip4_route_cmp(route_a, route_b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)); +} + +static gboolean +_ecmp_track_init_merged_obj(EcmpTrackEcmpid *track_ecmpid, const NMPObject **out_obj_del) +{ + EcmpTrackObj *track_obj; + nm_auto_nmpobj const NMPObject *obj_new = NULL; + gsize n_nexthops; + gsize i; + + nm_assert(track_ecmpid); + nm_assert(!c_list_is_empty(&track_ecmpid->ecmpid_lst_head)); + nm_assert(track_ecmpid->representative_obj + == c_list_first_entry(&track_ecmpid->ecmpid_lst_head, EcmpTrackObj, ecmpid_lst)->obj); + nm_assert(out_obj_del && !*out_obj_del); + + if (!track_ecmpid->needs_update) { + /* Already up to date. Nothing to do. */ + return FALSE; + } + + track_ecmpid->needs_update = FALSE; + + n_nexthops = c_list_length(&track_ecmpid->ecmpid_lst_head); + + if (n_nexthops == 1) { + /* There is only a single entry. There is nothing to merge, just set + * the first entry. */ + obj_new = nmp_object_ref(track_ecmpid->representative_obj); + goto out; + } + + /* We want that the nexthop list is deterministic. We thus sort the list and update + * the representative_obj. */ + c_list_sort(&track_ecmpid->ecmpid_lst_head, _ecmp_track_sort_lst_cmp, NULL); + nmp_object_ref_set( + &track_ecmpid->representative_obj, + c_list_first_entry(&track_ecmpid->ecmpid_lst_head, EcmpTrackObj, ecmpid_lst)->obj); + + obj_new = nmp_object_clone(track_ecmpid->representative_obj, FALSE); + + nm_assert(obj_new->ip4_route.n_nexthops <= 1); + nm_assert(!obj_new->_ip4_route.extra_nexthops); + + /* Note that there actually cannot be duplicate (ifindex,gateway,weight) tuples, because + * NML3Cfg uses NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID to track the routes, and track_ecmpid + * groups them further by NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID. The comparison for + * ECMP_ID is a strict superset of ID, hence there are no dupliated. + * + * Also, kernel wouldn't care if there were duplicate nexthops anyway. + * + * This means, it's gonna be simple. We sorted the single-hop routes by next-hop, + * now just create a plain list of the nexthops (no check for duplciates, etc). */ + + ((NMPObject *) obj_new)->ip4_route.n_nexthops = n_nexthops; + ((NMPObject *) obj_new)->_ip4_route.extra_nexthops = + g_new(NMPlatformIP4RtNextHop, n_nexthops - 1u); + + i = 0; + c_list_for_each_entry (track_obj, &track_ecmpid->ecmpid_lst_head, ecmpid_lst) { + if (i > 0) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(track_obj->obj); + NMPlatformIP4RtNextHop *nh = (gpointer) &obj_new->_ip4_route.extra_nexthops[i - 1]; + + *nh = (NMPlatformIP4RtNextHop){ + .ifindex = r->ifindex, + .gateway = r->gateway, + .weight = r->weight, + }; + } + i++; + } + +out: + nm_assert(obj_new); + if (nmp_object_equal(track_ecmpid->merged_obj, obj_new)) + /* the objects are equal but the update was needed, for example if the + * routes were removed from kernel but not from our tracking + * dictionaries and therefore we tried to register them again. */ + return TRUE; + + if (track_ecmpid->merged_obj) + *out_obj_del = g_steal_pointer(&track_ecmpid->merged_obj); + track_ecmpid->merged_obj = g_steal_pointer(&obj_new); + return TRUE; +} + +/*****************************************************************************/ + NMPNetns * nm_netns_get_platform_netns(NMNetns *self) { @@ -93,21 +257,67 @@ nm_netns_get_multi_idx(NMNetns *self) /*****************************************************************************/ -typedef struct { - int ifindex; - guint32 signal_pending_obj_type_flags; - NML3Cfg *l3cfg; - CList signal_pending_lst; -} L3CfgData; +static guint +_ecmp_routes_by_ecmpid_hash(gconstpointer ptr) +{ + const NMPObject *const *p_obj = ptr; + + return nm_platform_ip4_route_hash(NMP_OBJECT_CAST_IP4_ROUTE(*p_obj), + NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID); +} + +static int +_ecmp_routes_by_ecmpid_equal(gconstpointer ptr_a, gconstpointer ptr_b) +{ + const NMPObject *const *p_obj_a = ptr_a; + const NMPObject *const *p_obj_b = ptr_b; + + return nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(*p_obj_a), + NMP_OBJECT_CAST_IP4_ROUTE(*p_obj_b), + NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID) + == 0; +} static void -_l3cfg_data_free(gpointer ptr) +_ecmp_routes_by_ecmpid_free(gpointer ptr) { - L3CfgData *l3cfg_data = ptr; + EcmpTrackEcmpid *track_ecmpid = ptr; + + c_list_unlink_stale(&track_ecmpid->ecmpid_lst_head); + nmp_object_unref(track_ecmpid->representative_obj); + nmp_object_unref(track_ecmpid->merged_obj); + nm_g_slice_free(track_ecmpid); +} - c_list_unlink_stale(&l3cfg_data->signal_pending_lst); +static void +_ecmp_routes_by_obj_free(gpointer ptr) +{ + EcmpTrackObj *track_obj = ptr; - nm_g_slice_free(l3cfg_data); + c_list_unlink_stale(&track_obj->ifindex_lst); + c_list_unlink_stale(&track_obj->ecmpid_lst); + nmp_object_unref(track_obj->obj); + nm_g_slice_free(track_obj); +} + +/*****************************************************************************/ + +static NML3Cfg * +_l3cfg_hashed_to_l3cfg(gpointer ptr) +{ + gpointer l3cfg; + + l3cfg = &(((char *) ptr)[-G_STRUCT_OFFSET(NML3Cfg, priv.ifindex)]); + nm_assert(NM_IS_L3CFG(l3cfg)); + return l3cfg; +} + +static void +_l3cfg_hashed_free(gpointer ptr) +{ + NML3Cfg *l3cfg = _l3cfg_hashed_to_l3cfg(ptr); + + c_list_unlink(&l3cfg->internal_netns.signal_pending_lst); } static void @@ -128,58 +338,48 @@ _l3cfg_weak_notify(gpointer data, GObject *where_the_object_was) NML3Cfg * nm_netns_l3cfg_get(NMNetns *self, int ifindex) { - NMNetnsPrivate *priv; - L3CfgData *l3cfg_data; - - g_return_val_if_fail(NM_IS_NETNS(self), NULL); - g_return_val_if_fail(ifindex > 0, NULL); - - priv = NM_NETNS_GET_PRIVATE(self); + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self); + gpointer ptr; - l3cfg_data = g_hash_table_lookup(priv->l3cfgs, &ifindex); + nm_assert(ifindex > 0); - return l3cfg_data ? l3cfg_data->l3cfg : NULL; + ptr = g_hash_table_lookup(priv->l3cfgs, &ifindex); + return ptr ? _l3cfg_hashed_to_l3cfg(ptr) : NULL; } NML3Cfg * nm_netns_l3cfg_acquire(NMNetns *self, int ifindex) { NMNetnsPrivate *priv; - L3CfgData *l3cfg_data; + NML3Cfg *l3cfg; g_return_val_if_fail(NM_IS_NETNS(self), NULL); g_return_val_if_fail(ifindex > 0, NULL); priv = NM_NETNS_GET_PRIVATE(self); - l3cfg_data = g_hash_table_lookup(priv->l3cfgs, &ifindex); - - if (l3cfg_data) { + l3cfg = nm_netns_l3cfg_get(self, ifindex); + if (l3cfg) { nm_log_trace(LOGD_CORE, "l3cfg[" NM_HASH_OBFUSCATE_PTR_FMT ",ifindex=%d] %s", - NM_HASH_OBFUSCATE_PTR(l3cfg_data->l3cfg), + NM_HASH_OBFUSCATE_PTR(l3cfg), ifindex, "referenced"); - return g_object_ref(l3cfg_data->l3cfg); + return g_object_ref(l3cfg); } - l3cfg_data = g_slice_new(L3CfgData); - *l3cfg_data = (L3CfgData){ - .ifindex = ifindex, - .l3cfg = nm_l3cfg_new(self, ifindex), - .signal_pending_lst = C_LIST_INIT(l3cfg_data->signal_pending_lst), - }; + l3cfg = nm_l3cfg_new(self, ifindex); - if (!g_hash_table_add(priv->l3cfgs, l3cfg_data)) + if (!g_hash_table_add(priv->l3cfgs, &l3cfg->priv.ifindex)) nm_assert_not_reached(); if (NM_UNLIKELY(g_hash_table_size(priv->l3cfgs) == 1)) g_object_ref(self); - g_object_weak_ref(G_OBJECT(l3cfg_data->l3cfg), _l3cfg_weak_notify, self); + g_object_weak_ref(G_OBJECT(l3cfg), _l3cfg_weak_notify, self); /* Transfer ownership! We keep only a weak ref. */ - return l3cfg_data->l3cfg; + return l3cfg; } /*****************************************************************************/ @@ -189,7 +389,7 @@ _platform_signal_on_idle_cb(gpointer user_data) { gs_unref_object NMNetns *self = g_object_ref(NM_NETNS(user_data)); NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self); - L3CfgData *l3cfg_data; + NML3Cfg *l3cfg; CList work_list; nm_clear_g_source_inst(&priv->signal_pending_idle_source); @@ -205,12 +405,12 @@ _platform_signal_on_idle_cb(gpointer user_data) c_list_init(&work_list); c_list_splice(&work_list, &priv->l3cfg_signal_pending_lst_head); - while ((l3cfg_data = c_list_first_entry(&work_list, L3CfgData, signal_pending_lst))) { - nm_assert(NM_IS_L3CFG(l3cfg_data->l3cfg)); - c_list_unlink(&l3cfg_data->signal_pending_lst); + while ((l3cfg = c_list_first_entry(&work_list, NML3Cfg, internal_netns.signal_pending_lst))) { + nm_assert(NM_IS_L3CFG(l3cfg)); + c_list_unlink(&l3cfg->internal_netns.signal_pending_lst); _nm_l3cfg_notify_platform_change_on_idle( - l3cfg_data->l3cfg, - nm_steal_int(&l3cfg_data->signal_pending_obj_type_flags)); + l3cfg, + nm_steal_int(&l3cfg->internal_netns.signal_pending_obj_type_flags)); } return G_SOURCE_CONTINUE; @@ -228,24 +428,28 @@ _platform_signal_cb(NMPlatform *platform, NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self); const NMPObjectType obj_type = obj_type_i; const NMPlatformSignalChangeType change_type = change_type_i; - L3CfgData *l3cfg_data; + NML3Cfg *l3cfg; - l3cfg_data = g_hash_table_lookup(priv->l3cfgs, &ifindex); - if (!l3cfg_data) + if (ifindex <= 0) { + /* platform signal callback could be triggered by nodev routes, skip them */ + return; + } + + l3cfg = nm_netns_l3cfg_get(self, ifindex); + if (!l3cfg) return; - l3cfg_data->signal_pending_obj_type_flags |= nmp_object_type_to_flags(obj_type); + l3cfg->internal_netns.signal_pending_obj_type_flags |= nmp_object_type_to_flags(obj_type); - if (c_list_is_empty(&l3cfg_data->signal_pending_lst)) { - c_list_link_tail(&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst); + if (c_list_is_empty(&l3cfg->internal_netns.signal_pending_lst)) { + c_list_link_tail(&priv->l3cfg_signal_pending_lst_head, + &l3cfg->internal_netns.signal_pending_lst); if (!priv->signal_pending_idle_source) priv->signal_pending_idle_source = nm_g_idle_add_source(_platform_signal_on_idle_cb, self); } - _nm_l3cfg_notify_platform_change(l3cfg_data->l3cfg, - change_type, - NMP_OBJECT_UP_CAST(platform_object)); + _nm_l3cfg_notify_platform_change(l3cfg, change_type, NMP_OBJECT_UP_CAST(platform_object)); } /*****************************************************************************/ @@ -257,7 +461,7 @@ nm_netns_shared_ip_reserve(NMNetns *self) NMNetnsSharedIPHandle *handle; const in_addr_t addr_start = ntohl(0x0a2a0001u); /* 10.42.0.1 */ in_addr_t addr; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; /* Find an unused address in the 10.42.x.x range */ @@ -287,10 +491,10 @@ nm_netns_shared_ip_reserve(NMNetns *self) if (count > 0xFFu) { if (handle->_ref_count == 1) { _LOGE("shared-ip4: ran out of shared IP addresses. Reuse %s/24", - _nm_utils_inet4_ntop(handle->addr, sbuf_addr)); + nm_inet4_ntop(handle->addr, sbuf_addr)); } else { _LOGD("shared-ip4: reserved IP address range %s/24 (duplicate)", - _nm_utils_inet4_ntop(handle->addr, sbuf_addr)); + nm_inet4_ntop(handle->addr, sbuf_addr)); } handle->_ref_count++; return handle; @@ -307,8 +511,7 @@ nm_netns_shared_ip_reserve(NMNetns *self) g_hash_table_add(priv->shared_ips, handle); - _LOGD("shared-ip4: reserved IP address range %s/24", - _nm_utils_inet4_ntop(handle->addr, sbuf_addr)); + _LOGD("shared-ip4: reserved IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); return handle; } @@ -317,7 +520,7 @@ nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) { NMNetns *self; NMNetnsPrivate *priv; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; g_return_if_fail(handle); @@ -334,7 +537,7 @@ nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) nm_assert(handle->addr == ntohl(0x0A2AFF01u)); /* 10.42.255.1 */ handle->_ref_count--; _LOGD("shared-ip4: release IP address range %s/24 (%d more references held)", - _nm_utils_inet4_ntop(handle->addr, sbuf_addr), + nm_inet4_ntop(handle->addr, sbuf_addr), handle->_ref_count); return; } @@ -347,8 +550,7 @@ nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) g_object_unref(self); } - _LOGD("shared-ip4: release IP address range %s/24", - _nm_utils_inet4_ntop(handle->addr, sbuf_addr)); + _LOGD("shared-ip4: release IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); handle->_self = NULL; nm_g_slice_free(handle); @@ -356,6 +558,270 @@ nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) /*****************************************************************************/ +void +nm_netns_ip_route_ecmp_register(NMNetns *self, NML3Cfg *l3cfg, const NMPObject *obj) +{ + NMNetnsPrivate *priv; + EcmpTrackObj *track_obj; + const NMPlatformIP4Route *route; + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + + nm_assert_l3cfg(self, l3cfg); + + route = NMP_OBJECT_CAST_IP4_ROUTE(obj); + + nm_assert(route->ifindex > 0); + nm_assert(route->ifindex == nm_l3cfg_get_ifindex(l3cfg)); + nm_assert(route->n_nexthops <= 1); + + priv = NM_NETNS_GET_PRIVATE(self); + + track_obj = g_hash_table_lookup(priv->ecmp_track_by_obj, &obj); + + if (NM_MORE_ASSERTS > 10) { + EcmpTrackObj *track_obj2; + gboolean found = FALSE; + + c_list_for_each_entry (track_obj2, + &l3cfg->internal_netns.ecmp_track_ifindex_lst_head, + ifindex_lst) { + if (track_obj2->obj == obj) { + found = TRUE; + break; + } + } + + nm_assert((!!track_obj) == found); + } + + if (!track_obj) { + EcmpTrackEcmpid *track_ecmpid; + + track_ecmpid = g_hash_table_lookup(priv->ecmp_track_by_ecmpid, &obj); + if (!track_ecmpid) { + track_ecmpid = g_slice_new(EcmpTrackEcmpid); + *track_ecmpid = (EcmpTrackEcmpid){ + .representative_obj = nmp_object_ref(obj), + .merged_obj = NULL, + .ecmpid_lst_head = C_LIST_INIT(track_ecmpid->ecmpid_lst_head), + .needs_update = TRUE, + }; + g_hash_table_add(priv->ecmp_track_by_ecmpid, track_ecmpid); + } else + track_ecmpid->needs_update = TRUE; + + track_obj = g_slice_new(EcmpTrackObj); + *track_obj = (EcmpTrackObj){ + .obj = nmp_object_ref(obj), + .l3cfg = l3cfg, + .parent_track_ecmpid = track_ecmpid, + .dirty = FALSE, + .is_new = TRUE, + .is_ready = FALSE, + }; + + g_hash_table_add(priv->ecmp_track_by_obj, track_obj); + c_list_link_tail(&l3cfg->internal_netns.ecmp_track_ifindex_lst_head, + &track_obj->ifindex_lst); + c_list_link_tail(&track_ecmpid->ecmpid_lst_head, &track_obj->ecmpid_lst); + + _LOGT( + "ecmp-route: track %s", + nmp_object_to_string(track_obj->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + } else { + track_obj->dirty = FALSE; + track_obj->parent_track_ecmpid->needs_update = TRUE; + } +} + +void +nm_netns_ip_route_ecmp_commit(NMNetns *self, + NML3Cfg *l3cfg, + GPtrArray **out_singlehop_routes, + gboolean is_reapply) +{ + NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self); + EcmpTrackObj *track_obj; + EcmpTrackObj *track_obj_safe; + EcmpTrackEcmpid *track_ecmpid; + const NMPObject *route_obj; + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + gboolean already_notified = FALSE; + + nm_assert_l3cfg(self, l3cfg); + + _LOGT("ecmp-route: committing IPv4 ECMP routes"); + + /* First, delete all dirty entries, and mark the survivors as dirty, so that on the + * next update they must be touched again. */ + c_list_for_each_entry_safe (track_obj, + track_obj_safe, + &l3cfg->internal_netns.ecmp_track_ifindex_lst_head, + ifindex_lst) { + track_ecmpid = track_obj->parent_track_ecmpid; + track_ecmpid->already_visited = FALSE; + + nm_assert(g_hash_table_lookup(priv->ecmp_track_by_ecmpid, track_ecmpid) == track_ecmpid); + nm_assert(g_hash_table_lookup(priv->ecmp_track_by_obj, track_obj) == track_obj); + nm_assert(c_list_contains(&track_ecmpid->ecmpid_lst_head, &track_obj->ecmpid_lst)); + nm_assert(track_obj->l3cfg == l3cfg); + + if (!track_obj->dirty) { + /* This one is still in used. Keep it, but mark dirty, so that on the + * next update cycle, it needs to be touched again or will be deleted. */ + track_obj->dirty = TRUE; + if (is_reapply) { + track_obj->is_new = TRUE; + track_obj->is_ready = FALSE; + } + if (track_obj->is_new) { + const NMPlatformIP4Route *route = + NMP_OBJECT_CAST_IP4_ROUTE(track_ecmpid->merged_obj); + + /* This is a new route entry that was just added. Upon first + * addition, the route is not yet ready for configuration, + * because we need to make sure that the gateway is reachable + * via an onlink route. The calling l3cfg will configure that + * route, but only after returning from this function. So we + * need to go through one more commit. + * + * We also need to make sure that we are called back right + * after l3cfg configured that route. We achieve that by + * scheduling another idle commit on "l3cfg". */ + track_obj->is_new = FALSE; + if (route + && (route->gateway == 0 + || NM_FLAGS_HAS(route->r_rtm_flags, (unsigned) RTNH_F_ONLINK))) { + /* This route is onlink. We don't need to configure an onlink route + * to the gateway, and the route is immediately ready for configuration. */ + track_obj->is_ready = TRUE; + } else if (c_list_length_is(&track_ecmpid->ecmpid_lst_head, 1)) { + /* This route has no merge partner and ends up being a + * single hop route. It will be returned and configured by + * the calling "l3cfg". + * + * Unlike for multi-hop routes, we don't need to be called + * again after the onlink route was added. We are done, and + * don't need to schedule an idle commit. */ + track_obj->is_ready = TRUE; + } else { + /* This is a new route which has a gateway. We need for the "l3cfg" + * to first configure the onlink route. It's not yet ready for configuration. + * + * Instead, schedule an idle commit to make sure we get called back + * again, and then (upon seeing the entry the second time) the onlink + * route is already configured and we will be ready. */ + if (!already_notified) { + /* Some micro optimization with already_notified to avoid calling + * schedule unnecessarily. */ + already_notified = TRUE; + nm_l3cfg_commit_on_idle_schedule(l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); + } + } + } else { + /* We see this entry the second time (or more) so it's ready. */ + track_obj->is_ready = TRUE; + } + continue; + } + + /* This entry can be dropped. */ + if (!g_hash_table_remove(priv->ecmp_track_by_obj, track_obj)) + nm_assert_not_reached(); + + if (c_list_is_empty(&track_ecmpid->ecmpid_lst_head)) { + if (track_ecmpid->merged_obj) { + if (NMP_OBJECT_CAST_IP4_ROUTE(track_ecmpid->merged_obj)->n_nexthops > 1) + nm_platform_object_delete(priv->platform, track_ecmpid->merged_obj); + } + g_hash_table_remove(priv->ecmp_track_by_ecmpid, track_ecmpid); + + continue; + } + + /* We need to update the representative obj. */ + nmp_object_ref_set( + &track_ecmpid->representative_obj, + c_list_first_entry(&track_ecmpid->ecmpid_lst_head, EcmpTrackObj, ecmpid_lst)->obj); + track_ecmpid->needs_update = TRUE; + } + + /* Now, we need to iterate again over all objects, and regenerate the merged_obj. */ + c_list_for_each_entry (track_obj, + &l3cfg->internal_netns.ecmp_track_ifindex_lst_head, + ifindex_lst) { + const NMPlatformIP4Route *route; + EcmpTrackObj *track_obj2; + nm_auto_nmpobj const NMPObject *obj_del = NULL; + gboolean changed; + gboolean all_is_ready; + + track_ecmpid = track_obj->parent_track_ecmpid; + if (track_ecmpid->already_visited) { + /* We already visited this ecmpid in the same loop. We can skip, otherwise + * we might add the same route twice. */ + continue; + } + track_ecmpid->already_visited = TRUE; + + all_is_ready = TRUE; + c_list_for_each_entry (track_obj2, &track_ecmpid->ecmpid_lst_head, ecmpid_lst) { + if (!track_obj2->is_ready) { + all_is_ready = FALSE; + break; + } + } + if (!all_is_ready) { + /* Here we might have a merged_obj already which can have the wrong + * setting e.g the wrong nexthops. We leave them for the moment and + * then we reconfigure it when this entry is ready. */ + continue; + } + + changed = _ecmp_track_init_merged_obj(track_obj->parent_track_ecmpid, &obj_del); + + nm_assert(!obj_del || changed); + + route_obj = track_ecmpid->merged_obj; + route = NMP_OBJECT_CAST_IP4_ROUTE(route_obj); + + if (obj_del) { + if (NMP_OBJECT_CAST_IP4_ROUTE(obj_del)->n_nexthops > 1) + nm_platform_object_delete(priv->platform, obj_del); + else if (track_obj->l3cfg != l3cfg) + nm_l3cfg_commit_on_idle_schedule(track_obj->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); + } + + if (route->n_nexthops <= 1) { + /* This is a single hop route. Return it to the caller. */ + if (!*out_singlehop_routes) { + /* Note that the returned array does not own a reference. This + * function has only one caller, and for that caller, it's just + * fine that the result is not additionally kept alive. */ + *out_singlehop_routes = + g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + } + g_ptr_array_add(*out_singlehop_routes, (gpointer) nmp_object_ref(route_obj)); + if (changed) { + _LOGT("ecmp-route: single-hop %s", + nmp_object_to_string(route_obj, + NMP_OBJECT_TO_STRING_PUBLIC, + sbuf, + sizeof(sbuf))); + } + continue; + } + + if (changed || is_reapply) { + _LOGT("ecmp-route: multi-hop %s", + nmp_object_to_string(route_obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + nm_platform_ip_route_add(priv->platform, NMP_NLM_FLAG_APPEND, route_obj); + } + } +} + +/*****************************************************************************/ + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { @@ -385,6 +851,14 @@ nm_netns_init(NMNetns *self) priv->_self_signal_user_data = self; c_list_init(&priv->l3cfg_signal_pending_lst_head); + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(EcmpTrackObj, obj) == 0); + priv->ecmp_track_by_obj = + g_hash_table_new_full(nm_pdirect_hash, nm_pdirect_equal, _ecmp_routes_by_obj_free, NULL); + priv->ecmp_track_by_ecmpid = g_hash_table_new_full(_ecmp_routes_by_ecmpid_hash, + _ecmp_routes_by_ecmpid_equal, + _ecmp_routes_by_ecmpid_free, + NULL); } static void @@ -396,7 +870,7 @@ constructed(GObject *object) if (!priv->platform) g_return_if_reached(); - priv->l3cfgs = g_hash_table_new_full(nm_pint_hash, nm_pint_equal, _l3cfg_data_free, NULL); + priv->l3cfgs = g_hash_table_new_full(nm_pint_hash, nm_pint_equal, _l3cfg_hashed_free, NULL); priv->platform_netns = nm_platform_netns_get(priv->platform); @@ -464,6 +938,9 @@ dispose(GObject *object) nm_assert(c_list_is_empty(&priv->l3cfg_signal_pending_lst_head)); nm_assert(!priv->shared_ips); + nm_clear_pointer(&priv->ecmp_track_by_obj, g_hash_table_destroy); + nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy); + nm_clear_g_source_inst(&priv->signal_pending_idle_source); if (priv->platform) diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index 17c1c637..84a78f83 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -9,7 +9,7 @@ #include "libnm-platform/nmp-base.h" #define NM_TYPE_NETNS (nm_netns_get_type()) -#define NM_NETNS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NETNS, NMNetns)) +#define NM_NETNS(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NETNS, NMNetns)) #define NM_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_NETNS, NMNetnsClass)) #define NM_IS_NETNS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_NETNS)) #define NM_IS_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_NETNS)) @@ -51,4 +51,12 @@ NMNetnsSharedIPHandle *nm_netns_shared_ip_reserve(NMNetns *self); void nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle); +/*****************************************************************************/ + +void nm_netns_ip_route_ecmp_register(NMNetns *self, NML3Cfg *l3cfg, const NMPObject *obj); +void nm_netns_ip_route_ecmp_commit(NMNetns *self, + NML3Cfg *l3cfg, + GPtrArray **routes, + gboolean is_reapply); + #endif /* __NM_NETNS_H__ */ diff --git a/src/core/nm-pacrunner-manager.c b/src/core/nm-pacrunner-manager.c index 86a40632..80db755f 100644 --- a/src/core/nm-pacrunner-manager.c +++ b/src/core/nm-pacrunner-manager.c @@ -129,7 +129,7 @@ get_ip_domains(GPtrArray *domains, const NML3ConfigData *l3cd, int addr_family) char *cidr; guint num; guint i; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; const NMPlatformIPAddress *address; const NMPlatformIPRoute *route; const char *const *strv; @@ -144,7 +144,7 @@ get_ip_domains(GPtrArray *domains, const NML3ConfigData *l3cd, int addr_family) nm_l3_config_data_iter_ip_address_for_each (&ipconf_iter, l3cd, addr_family, &address) { cidr = g_strdup_printf("%s/%u", - nm_utils_inet_ntop(addr_family, address->address_ptr, sbuf), + nm_inet_ntop(addr_family, address->address_ptr, sbuf), address->plen); g_ptr_array_add(domains, cidr); } @@ -153,7 +153,7 @@ get_ip_domains(GPtrArray *domains, const NML3ConfigData *l3cd, int addr_family) if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) continue; cidr = g_strdup_printf("%s/%u", - nm_utils_inet_ntop(addr_family, route->network_ptr, sbuf), + nm_inet_ntop(addr_family, route->network_ptr, sbuf), route->plen); g_ptr_array_add(domains, cidr); } diff --git a/src/core/nm-pacrunner-manager.h b/src/core/nm-pacrunner-manager.h index 3f16908f..b434349a 100644 --- a/src/core/nm-pacrunner-manager.h +++ b/src/core/nm-pacrunner-manager.h @@ -9,7 +9,7 @@ #define NM_TYPE_PACRUNNER_MANAGER (nm_pacrunner_manager_get_type()) #define NM_PACRUNNER_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManager)) #define NM_PACRUNNER_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_PACRUNNER_MANAGER, NMPacrunnerManagerClass)) #define NM_IS_PACRUNNER_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_PACRUNNER_MANAGER)) diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 0c07c29e..d7e05b7b 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -108,9 +108,10 @@ _PRIV_TO_SELF(NMPolicyPrivate *priv) nm_assert(priv); - self = (NMPolicy *) (((char *) priv) - G_STRUCT_OFFSET(NMPolicy, _priv)); + self = NM_CAST_ALIGN(NMPolicy, (((char *) priv) - G_STRUCT_OFFSET(NMPolicy, _priv))); nm_assert(NM_IS_POLICY(self)); + return self; } @@ -167,11 +168,11 @@ static void clear_ip6_prefix_delegation(gpointer data) { IP6PrefixDelegation *delegation = data; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; _LOGD(LOGD_IP6, "ipv6-pd: undelegating prefix %s/%d", - _nm_utils_inet6_ntop(&delegation->prefix.address, sbuf), + nm_inet6_ntop(&delegation->prefix.address, sbuf), delegation->prefix.plen); g_hash_table_foreach(delegation->subnets, _clear_ip6_subnet, NULL); @@ -187,7 +188,7 @@ expire_ip6_delegations(NMPolicy *self) guint i; for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { - delegation = &g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + delegation = &nm_g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); if (delegation->prefix.timestamp + delegation->prefix.lifetime < now) g_array_remove_index_fast(priv->ip6_prefix_delegations, i); } @@ -204,7 +205,7 @@ ip6_subnet_from_delegation(IP6PrefixDelegation *delegation, NMDevice *device) { NMPlatformIP6Address *subnet; int ifindex = nm_device_get_ifindex(device); - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; subnet = g_hash_table_lookup(delegation->subnets, GINT_TO_POINTER(ifindex)); if (!subnet) { @@ -212,7 +213,7 @@ ip6_subnet_from_delegation(IP6PrefixDelegation *delegation, NMDevice *device) if (delegation->next_subnet >= (1 << (64 - delegation->prefix.plen))) { _LOGD(LOGD_IP6, "ipv6-pd: no more prefixes in %s/%d", - _nm_utils_inet6_ntop(&delegation->prefix.address, sbuf), + nm_inet6_ntop(&delegation->prefix.address, sbuf), delegation->prefix.plen); return FALSE; } @@ -241,7 +242,7 @@ ip6_subnet_from_delegation(IP6PrefixDelegation *delegation, NMDevice *device) _LOGD(LOGD_IP6, "ipv6-pd: %s allocated from a /%d prefix on %s", - _nm_utils_inet6_ntop(&subnet->address, sbuf), + nm_inet6_ntop(&subnet->address, sbuf), delegation->prefix.plen, nm_device_get_iface(device)); @@ -267,7 +268,7 @@ ip6_subnet_from_device(NMPolicy *self, NMDevice *from_device, NMDevice *device) expire_ip6_delegations(self); for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { - delegation = &g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + delegation = &nm_g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); if (delegation->device != from_device) continue; @@ -295,7 +296,7 @@ ip6_remove_device_prefix_delegations(NMPolicy *self, NMDevice *device) guint i; for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { - delegation = &g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + delegation = &nm_g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); if (delegation->device == device) g_array_remove_index_fast(priv->ip6_prefix_delegations, i); } @@ -312,11 +313,11 @@ device_ip6_prefix_delegated(NMDevice *device, guint i; const CList *tmp_list; NMActiveConnection *ac; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; _LOGI(LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s", - _nm_utils_inet6_ntop(&prefix->address, sbuf), + nm_inet6_ntop(&prefix->address, sbuf), prefix->plen, nm_device_get_iface(device)); @@ -324,16 +325,15 @@ device_ip6_prefix_delegated(NMDevice *device, for (i = 0; i < priv->ip6_prefix_delegations->len; i++) { /* Look for an already known prefix to update. */ - delegation = &g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); + delegation = &nm_g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); if (IN6_ARE_ADDR_EQUAL(&delegation->prefix.address, &prefix->address)) break; } if (i == priv->ip6_prefix_delegations->len) { /* Allocate a delegation for new prefix. */ - g_array_set_size(priv->ip6_prefix_delegations, i + 1); - delegation = &g_array_index(priv->ip6_prefix_delegations, IP6PrefixDelegation, i); - delegation->subnets = g_hash_table_new(nm_direct_hash, NULL); + delegation = nm_g_array_append_new(priv->ip6_prefix_delegations, IP6PrefixDelegation); + delegation->subnets = g_hash_table_new(nm_direct_hash, NULL); delegation->next_subnet = 0; } @@ -458,7 +458,7 @@ get_best_active_connection(NMPolicy *self, int addr_family, gboolean fully_activ } static gboolean -all_devices_not_active(NMPolicy *self) +any_devices_active(NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); const CList *tmp_lst; @@ -468,12 +468,13 @@ all_devices_not_active(NMPolicy *self) NMDeviceState state; state = nm_device_get_state(device); - if (state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) { + if (state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) continue; - } - return FALSE; + if (nm_device_sys_iface_state_is_external(device)) + continue; + return TRUE; } - return TRUE; + return FALSE; } #define FALLBACK_HOSTNAME4 "localhost.localdomain" @@ -607,7 +608,7 @@ _set_hostname(NMPolicy *self, const char *new_hostname, const char *msg) priv->updating_dns = TRUE; nm_dns_manager_set_hostname(priv->dns_manager, priv->cur_hostname_full, - all_devices_not_active(self)); + !any_devices_active(self)); priv->updating_dns = FALSE; } @@ -738,6 +739,9 @@ build_device_hostname_infos(NMPolicy *self) if (!device) continue; + if (nm_device_sys_iface_state_is_external(device)) + continue; + only_from_default = device_get_hostname_property_boolean(device, NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT); @@ -770,10 +774,10 @@ build_device_hostname_infos(NMPolicy *self) g_array_sort(array, device_hostname_info_compare); - info0 = &g_array_index(array, DeviceHostnameInfo, 0); + info0 = &nm_g_array_first(array, DeviceHostnameInfo); if (info0->priority < 0) { for (i = 1; i < array->len; i++) { - const DeviceHostnameInfo *info = &g_array_index(array, DeviceHostnameInfo, i); + const DeviceHostnameInfo *info = &nm_g_array_index(array, DeviceHostnameInfo, i); if (info->priority > info0->priority) { g_array_set_size(array, i); @@ -878,7 +882,7 @@ update_system_hostname(NMPolicy *self, const char *msg) if (infos && _LOGT_ENABLED(LOGD_DNS)) { _LOGT(LOGD_DNS, "device hostname info:"); for (i = 0; i < infos->len; i++) { - info = &g_array_index(infos, DeviceHostnameInfo, i); + info = &nm_g_array_index(infos, DeviceHostnameInfo, i); _LOGT(LOGD_DNS, " - prio:%5d ipv%c%s %s %s dev:%s", info->priority, @@ -891,7 +895,7 @@ update_system_hostname(NMPolicy *self, const char *msg) } for (i = 0; infos && i < infos->len; i++) { - info = &g_array_index(infos, DeviceHostnameInfo, i); + info = &nm_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); @@ -1361,8 +1365,16 @@ auto_activate_device(NMPolicy *self, NMDevice *device) // but another connection now overrides the current one for that device, // deactivate the device and activate the new connection instead of just // bailing if the device is already active - if (nm_device_get_act_request(device)) - return; + if (nm_device_get_act_request(device)) { + if (nm_device_sys_iface_state_is_external(device) + && nm_device_get_allow_autoconnect_on_external(device)) { + /* this is an external activation, and we allow autoconnecting on + * top of that. + * + * pass. */ + } else + return; + } if (!nm_device_autoconnect_allowed(device)) return; @@ -1689,8 +1701,13 @@ schedule_activate_check(NMPolicy *self, NMDevice *device) return; nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - if (nm_active_connection_get_device(ac) == device) - return; + if (nm_active_connection_get_device(ac) == device) { + if (nm_device_sys_iface_state_is_external(device) + && nm_device_get_allow_autoconnect_on_external(device)) { + /* pass */ + } else + return; + } } nm_device_add_pending_action(device, NM_PENDING_ACTION_AUTOACTIVATE, TRUE); @@ -2564,7 +2581,7 @@ dns_config_changed(NMDnsManager *dns_manager, gpointer user_data) return; nm_manager_for_each_device (priv->manager, device, tmp_lst) { - nm_device_clear_dns_lookup_data(device); + nm_device_clear_dns_lookup_data(device, "DNS configuration changed"); } update_system_hostname(self, "DNS configuration changed"); diff --git a/src/core/nm-policy.h b/src/core/nm-policy.h index fa216db3..f2b98dbd 100644 --- a/src/core/nm-policy.h +++ b/src/core/nm-policy.h @@ -8,7 +8,7 @@ #define __NETWORKMANAGER_POLICY_H__ #define NM_TYPE_POLICY (nm_policy_get_type()) -#define NM_POLICY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_POLICY, NMPolicy)) +#define NM_POLICY(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_POLICY, NMPolicy)) #define NM_POLICY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_POLICY, NMPolicyClass)) #define NM_IS_POLICY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_POLICY)) #define NM_IS_POLICY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_POLICY)) diff --git a/src/core/nm-rfkill-manager.h b/src/core/nm-rfkill-manager.h index 88d0421a..818ab4b2 100644 --- a/src/core/nm-rfkill-manager.h +++ b/src/core/nm-rfkill-manager.h @@ -37,7 +37,7 @@ const char *nm_rfkill_type_to_string(NMRfkillType rtype); #define NM_TYPE_RFKILL_MANAGER (nm_rfkill_manager_get_type()) #define NM_RFKILL_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_RFKILL_MANAGER, NMRfkillManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_RFKILL_MANAGER, NMRfkillManager)) #define NM_RFKILL_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_RFKILL_MANAGER, NMRfkillManagerClass)) #define NM_IS_RFKILL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_RFKILL_MANAGER)) diff --git a/src/core/nm-session-monitor.h b/src/core/nm-session-monitor.h index 63a3136b..5b7c3f91 100644 --- a/src/core/nm-session-monitor.h +++ b/src/core/nm-session-monitor.h @@ -10,7 +10,7 @@ #define NM_TYPE_SESSION_MONITOR (nm_session_monitor_get_type()) #define NM_SESSION_MONITOR(o) \ - (G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitor)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_SESSION_MONITOR, NMSessionMonitor)) #define NM_SESSION_MONITOR_CLASS(k) \ (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_SESSION_MONITOR, NMSessionMonitorClass)) #define NM_SESSION_MONITOR_GET_CLASS(o) \ diff --git a/src/core/nm-sleep-monitor.c b/src/core/nm-sleep-monitor.c index a7ea496d..66ea2f6c 100644 --- a/src/core/nm-sleep-monitor.c +++ b/src/core/nm-sleep-monitor.c @@ -11,6 +11,7 @@ #include <sys/stat.h> #include <gio/gunixfdlist.h> +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" @@ -294,24 +295,24 @@ on_proxy_acquired(GObject *object, GAsyncResult *res, NMSleepMonitor *self) g_clear_object(&self->cancellable); #if USE_UPOWER - self->sig_id_1 = _nm_dbus_signal_connect(self->proxy, - "Sleeping", - NULL, - G_CALLBACK(upower_sleeping_cb), - self); - self->sig_id_2 = _nm_dbus_signal_connect(self->proxy, - "Resuming", - NULL, - G_CALLBACK(upower_resuming_cb), - self); + self->sig_id_1 = _nm_dbus_proxy_signal_connect(self->proxy, + "Sleeping", + NULL, + G_CALLBACK(upower_sleeping_cb), + self); + self->sig_id_2 = _nm_dbus_proxy_signal_connect(self->proxy, + "Resuming", + NULL, + G_CALLBACK(upower_resuming_cb), + self); #else self->sig_id_1 = g_signal_connect(self->proxy, "notify::g-name-owner", G_CALLBACK(name_owner_cb), self); - self->sig_id_2 = _nm_dbus_signal_connect(self->proxy, - "PrepareForSleep", - G_VARIANT_TYPE("(b)"), - G_CALLBACK(prepare_for_sleep_cb), - self); + self->sig_id_2 = _nm_dbus_proxy_signal_connect(self->proxy, + "PrepareForSleep", + G_VARIANT_TYPE("(b)"), + G_CALLBACK(prepare_for_sleep_cb), + self); { gs_free char *owner = NULL; diff --git a/src/core/nm-sleep-monitor.h b/src/core/nm-sleep-monitor.h index 7d45065b..0b7708db 100644 --- a/src/core/nm-sleep-monitor.h +++ b/src/core/nm-sleep-monitor.h @@ -8,7 +8,8 @@ #define __NETWORKMANAGER_SLEEP_MONITOR_H__ #define NM_TYPE_SLEEP_MONITOR (nm_sleep_monitor_get_type()) -#define NM_SLEEP_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_SLEEP_MONITOR, NMSleepMonitor)) +#define NM_SLEEP_MONITOR(o) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((o), NM_TYPE_SLEEP_MONITOR, NMSleepMonitor)) #define NM_SLEEP_MONITOR_CLASS(k) \ (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_SLEEP_MONITOR, NMSleepMonitorClass)) #define NM_SLEEP_MONITOR_GET_CLASS(o) \ diff --git a/src/core/nm-test-utils-core.h b/src/core/nm-test-utils-core.h index 467f9bb2..e341d62f 100644 --- a/src/core/nm-test-utils-core.h +++ b/src/core/nm-test-utils-core.h @@ -72,8 +72,8 @@ nmtst_platform_ip6_address(const char *address, const char *peer_address, guint g_assert(plen <= 128); memset(&addr, 0, sizeof(addr)); - addr.address = *nmtst_inet6_from_string(address); - addr.peer_address = *nmtst_inet6_from_string(peer_address); + addr.address = nmtst_inet6_from_string(address); + addr.peer_address = nmtst_inet6_from_string(peer_address); addr.plen = plen; return &addr; @@ -148,10 +148,10 @@ nmtst_platform_ip6_route(const char *network, guint plen, const char *gateway, c nm_assert(plen <= 128); memset(&route, 0, sizeof(route)); - route.network = *nmtst_inet6_from_string(network); + route.network = nmtst_inet6_from_string(network); route.plen = plen; - route.gateway = *nmtst_inet6_from_string(gateway); - route.pref_src = *nmtst_inet6_from_string(pref_src); + route.gateway = nmtst_inet6_from_string(gateway); + route.pref_src = nmtst_inet6_from_string(pref_src); return &route; } @@ -178,8 +178,9 @@ nmtst_platform_ip6_route_full(const char *network, static inline int _nmtst_platform_ip4_routes_equal_sort(gconstpointer a, gconstpointer b, gpointer user_data) { - return nm_platform_ip4_route_cmp_full((const NMPlatformIP4Route *) a, - (const NMPlatformIP4Route *) b); + return nm_platform_ip4_route_cmp((const NMPlatformIP4Route *) a, + (const NMPlatformIP4Route *) b, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); } static inline void @@ -210,7 +211,7 @@ nmtst_platform_ip4_routes_equal(const NMPlatformIP4Route *a, } for (i = 0; i < len; i++) { - if (nm_platform_ip4_route_cmp_full(&a[i], &b[i]) != 0) { + if (nm_platform_ip4_route_cmp(&a[i], &b[i], NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) { char buf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; char buf2[NM_UTILS_TO_STRING_BUFFER_SIZE]; @@ -248,8 +249,9 @@ nmtst_platform_ip4_routes_equal_aptr(const NMPObject *const *a, static inline int _nmtst_platform_ip6_routes_equal_sort(gconstpointer a, gconstpointer b, gpointer user_data) { - return nm_platform_ip6_route_cmp_full((const NMPlatformIP6Route *) a, - (const NMPlatformIP6Route *) b); + return nm_platform_ip6_route_cmp((const NMPlatformIP6Route *) a, + (const NMPlatformIP6Route *) b, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); } static inline void @@ -280,7 +282,7 @@ nmtst_platform_ip6_routes_equal(const NMPlatformIP6Route *a, } for (i = 0; i < len; i++) { - if (nm_platform_ip6_route_cmp_full(&a[i], &b[i]) != 0) { + if (nm_platform_ip6_route_cmp(&a[i], &b[i], NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) { char buf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; char buf2[NM_UTILS_TO_STRING_BUFFER_SIZE]; diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index a1ca5434..c92d9aef 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -170,7 +170,7 @@ link_get(NMPlatform *platform, int ifindex) if (idx >= priv->links->len) goto not_found; - device = &g_array_index(priv->links, NMFakePlatformLink, idx); + device = &nm_g_array_index(priv->links, NMFakePlatformLink, idx); if (!device->obj) goto not_found; @@ -234,8 +234,7 @@ link_add_pre(NMPlatform *platform, g_assert(!name || strlen(name) < IFNAMSIZ); - g_array_set_size(priv->links, priv->links->len + 1); - device = &g_array_index(priv->links, NMFakePlatformLink, priv->links->len - 1); + device = nm_g_array_append_new(priv->links, NMFakePlatformLink); ifindex = priv->links->len; memset(device, 0, sizeof(*device)); @@ -272,7 +271,7 @@ link_add_pre(NMPlatform *platform, g_assert(address_len == 0); device->obj = o; - device->ip6_lladdr = *nmtst_inet6_from_string(ip6_lladdr); + device->ip6_lladdr = nmtst_inet6_from_string(ip6_lladdr); return device; } @@ -980,7 +979,7 @@ ipx_address_delete(NMPlatform *platform, || (plen && address->plen != *plen) || (peer_addr && (((peer_addr_i ^ address->peer_address) - & _nm_utils_ip4_prefix_to_netmask(address->plen)) + & nm_ip4_addr_netmask_from_prefix(address->plen)) != 0))) continue; } else { @@ -1093,10 +1092,7 @@ object_delete(NMPlatform *platform, const NMPObject *obj) } static int -ip_route_add(NMPlatform *platform, - NMPNlmFlags flags, - int addr_family, - const NMPlatformIPRoute *route) +ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack) { NMDedupMultiIter iter; nm_auto_nmpobj NMPObject *obj = NULL; @@ -1110,23 +1106,29 @@ ip_route_add(NMPlatform *platform, NMPlatformIPRoute *r = NULL; NMPlatformIP4Route *r4 = NULL; NMPlatformIP6Route *r6 = NULL; + int addr_family; gboolean has_same_weak_id; gboolean only_dirty; guint16 nlmsgflags; - g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + g_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_stack), + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); + + addr_family = NMP_OBJECT_GET_ADDR_FAMILY(obj_stack); flags = NM_FLAGS_UNSET(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE); /* currently, only replace is implemented. */ g_assert(flags == NMP_NLM_FLAG_REPLACE); - obj = nmp_object_new(addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ROUTE - : NMP_OBJECT_TYPE_IP6_ROUTE, - (const NMPlatformObject *) route); - r = NMP_OBJECT_CAST_IP_ROUTE(obj); + if (NMP_OBJECT_GET_TYPE(obj_stack) == NMP_OBJECT_TYPE_IP4_ROUTE + && obj_stack->ip4_route.n_nexthops == 0 && obj_stack->ip4_route.ifindex > 0) + obj_stack->ip4_route.n_nexthops = 1; - nm_platform_ip_route_normalize(addr_family, r); + obj = nmp_object_clone(obj_stack, FALSE); + + r = NMP_OBJECT_CAST_IP_ROUTE(obj); switch (addr_family) { case AF_INET: @@ -1151,8 +1153,8 @@ ip_route_add(NMPlatform *platform, &o) { if (addr_family == AF_INET) { const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE(o); - guint32 n = nm_utils_ip4_address_clear_host_address(item->network, item->plen); - guint32 g = nm_utils_ip4_address_clear_host_address(r4->gateway, item->plen); + guint32 n = nm_ip4_addr_clear_host_address(item->network, item->plen); + guint32 g = nm_ip4_addr_clear_host_address(r4->gateway, item->plen); if (r->ifindex == item->ifindex && n == g) { has_route_to_gw = TRUE; @@ -1162,21 +1164,21 @@ ip_route_add(NMPlatform *platform, const NMPlatformIP6Route *item = NMP_OBJECT_CAST_IP6_ROUTE(o); if (r->ifindex == item->ifindex - && nm_utils_ip6_address_same_prefix(&r6->gateway, &item->network, item->plen)) { + && nm_ip6_addr_same_prefix(&r6->gateway, &item->network, item->plen)) { has_route_to_gw = TRUE; break; } } } if (!has_route_to_gw) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; if (addr_family == AF_INET) { nm_log_warn( LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable", r->ifindex, - _nm_utils_inet4_ntop(r4->network, sbuf), + nm_inet4_ntop(r4->network, sbuf), r->plen, r->metric); } else { @@ -1184,7 +1186,7 @@ ip_route_add(NMPlatform *platform, LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable", r->ifindex, - _nm_utils_inet6_ntop(&r6->network, sbuf), + nm_inet6_ntop(&r6->network, sbuf), r->plen, r->metric); } @@ -1230,6 +1232,7 @@ ip_route_add(NMPlatform *platform, obj, FALSE, nlmsgflags, + TRUE, &obj_old, &obj_new, &obj_replace, @@ -1292,7 +1295,7 @@ finalize(GObject *object) g_hash_table_unref(priv->options); for (i = 0; i < priv->links->len; i++) { - NMFakePlatformLink *device = &g_array_index(priv->links, NMFakePlatformLink, i); + NMFakePlatformLink *device = &nm_g_array_index(priv->links, NMFakePlatformLink, i); nm_clear_pointer(&device->obj, nmp_object_unref); } diff --git a/src/core/platform/nm-fake-platform.h b/src/core/platform/nm-fake-platform.h index 8f8571fa..88fd3243 100644 --- a/src/core/platform/nm-fake-platform.h +++ b/src/core/platform/nm-fake-platform.h @@ -10,7 +10,7 @@ #define NM_TYPE_FAKE_PLATFORM (nm_fake_platform_get_type()) #define NM_FAKE_PLATFORM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FAKE_PLATFORM, NMFakePlatform)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FAKE_PLATFORM, NMFakePlatform)) #define NM_FAKE_PLATFORM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_FAKE_PLATFORM, NMFakePlatformClass)) #define NM_IS_FAKE_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_FAKE_PLATFORM)) diff --git a/src/core/platform/tests/meson.build b/src/core/platform/tests/meson.build index 8824ed2f..252c6840 100644 --- a/src/core/platform/tests/meson.build +++ b/src/core/platform/tests/meson.build @@ -13,7 +13,7 @@ test_units = [ ['test-nmp-object', 'test-nmp-object.c', test_c_flags, default_test_timeout], ['test-platform-general', 'test-platform-general.c', test_c_flags, default_test_timeout], ['test-route-fake', 'test-route.c', test_fake_c_flags, default_test_timeout], - ['test-route-linux', 'test-route.c', test_linux_c_flags, default_test_timeout], + ['test-route-linux', 'test-route.c', test_linux_c_flags, 900], ['test-tc-linux', 'test-tc.c', test_linux_c_flags, default_test_timeout], ] diff --git a/src/core/platform/tests/monitor.c b/src/core/platform/tests/monitor.c index 8d0e0107..c83192bb 100644 --- a/src/core/platform/tests/monitor.c +++ b/src/core/platform/tests/monitor.c @@ -8,6 +8,8 @@ #include <stdlib.h> #include <syslog.h> +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "libnm-platform/nm-linux-platform.h" #include "libnm-platform/nmp-object.h" @@ -17,23 +19,45 @@ NMTST_DEFINE(); static struct { gboolean persist; + char *state_file; } global_opt = { .persist = TRUE, }; +const char *const *const ip_argv_rule6 = NM_MAKE_STRV("ip", "-d", "-6", "rule"); + +static const struct { + NMPObjectType obj_type; + const char *const *ip_argv; +} dump_obj_types[] = { + {NMP_OBJECT_TYPE_LINK, NM_MAKE_STRV("ip", "-d", "link")}, + {NMP_OBJECT_TYPE_IP4_ADDRESS, NM_MAKE_STRV("ip", "-d", "-4", "address")}, + {NMP_OBJECT_TYPE_IP6_ADDRESS, NM_MAKE_STRV("ip", "-d", "-6", "address")}, + {NMP_OBJECT_TYPE_IP4_ROUTE, NM_MAKE_STRV("ip", "-d", "-4", "route")}, + {NMP_OBJECT_TYPE_IP6_ROUTE, NM_MAKE_STRV("ip", "-d", "-6", "route")}, + {NMP_OBJECT_TYPE_ROUTING_RULE, NM_MAKE_STRV("ip", "-d", "-4", "rule")}, +}; + static gboolean read_argv(int *argc, char ***argv) { GOptionContext *context; GOptionEntry options[] = { - {"no-persist", + {"no-persist", 'P', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.persist, "Exit after processing netlink messages", NULL}, - {0}, + {"state-file", + 'S', + 0, + G_OPTION_ARG_FILENAME, + &global_opt.state_file, + "Dump the platform cache to this file", + "FILE"}, + {0}, }; gs_free_error GError *error = NULL; @@ -63,6 +87,123 @@ mptcp_addr_dump(NMPlatform *platform) /*****************************************************************************/ +static void +_dump_state(NMPlatform *platform, const char *state_file) +{ + nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_488, FALSE); + nm_auto_unref_gdatetime GDateTime *time_datetime = NULL; + gs_free char *time_str = NULL; + int i_obj_type; + + if (!state_file) + return; + + time_datetime = g_date_time_new_now_local(); + time_str = g_date_time_format(time_datetime, "%C%y-%m-%dT%H:%M:%S.%f"); + + nm_log_dbg(LOGD_PLATFORM, "dump to file \"%s\", at %s", state_file, time_str); + + nm_str_buf_append_printf(&sbuf, "time: %s\n", time_str); + nm_str_buf_append_printf(&sbuf, "pid: %lld\n", (long long) getpid()); + + for (i_obj_type = 0; i_obj_type < (int) G_N_ELEMENTS(dump_obj_types); i_obj_type++) { + NMPObjectType obj_type = dump_obj_types[i_obj_type].obj_type; + const char *const *ip_argv = dump_obj_types[i_obj_type].ip_argv; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter pl_iter; + const NMPObject *obj; + guint i; + char buf1[1000]; + + pl_head_entry = nm_platform_lookup_obj_type(platform, obj_type); + + nm_str_buf_append_printf(&sbuf, + "\n%s: %u\n", + nmp_class_from_type(obj_type)->obj_type_name, + pl_head_entry ? pl_head_entry->len : 0u); + + i = 0; + nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &obj) { + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, buf1, sizeof(buf1)); + nm_str_buf_append_printf(&sbuf, + "%s[%u]: %s\n", + nmp_class_from_type(obj_type)->obj_type_name, + i, + buf1); + g_assert(strlen(buf1) < sizeof(buf1) - 1u); + i++; + } + +ip_again: + if (ip_argv) { + gs_free_error GError *error = NULL; + gs_free char *ip_argv_ss = NULL; + gs_free char *s_stdout = NULL; + gs_free char *s_stderr = NULL; + int exit_code; + + g_spawn_sync(NULL, + (char **) ip_argv, + NULL, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + &s_stdout, + &s_stderr, + &exit_code, + &error); + + nm_str_buf_append_printf(&sbuf, + "%s: call %s: ", + nmp_class_from_type(obj_type)->obj_type_name, + ip_argv_ss = g_strjoinv(" ", (char **) ip_argv)); + if (error) { + nm_str_buf_append_printf(&sbuf, "FAILED: %s\n", error->message); + } else if (WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0) + nm_str_buf_append_printf(&sbuf, "SUCCESS\n"); + else { + nm_str_buf_append_printf( + &sbuf, + "ERROR: %s\n", + nm_utils_get_process_exit_status_desc_buf(exit_code, buf1, sizeof(buf1))); + } + if (!nm_str_is_empty(s_stdout)) + nm_str_buf_append_printf(&sbuf, "STDOUT>\n%s<\n", s_stdout); + if (!nm_str_is_empty(s_stderr)) + nm_str_buf_append_printf(&sbuf, "STDERR>\n%s<\n", s_stderr); + + if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE + && ip_argv == dump_obj_types[i_obj_type].ip_argv) { + ip_argv = ip_argv_rule6; + goto ip_again; + } + } + } + + nm_utils_file_set_contents(state_file, + nm_str_buf_get_str_unsafe(&sbuf), + sbuf.len, + 00644, + NULL, + NULL, + NULL); + + nm_log_dbg(LOGD_PLATFORM, "dump to file complete"); +} + +static void +_dump_state_platform_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + gconstpointer platform_object, + int change_type_i, + gpointer unused_user_data) +{ + _dump_state(platform, global_opt.state_file); +} + +/*****************************************************************************/ + int main(int argc, char **argv) { @@ -82,12 +223,32 @@ main(int argc, char **argv) nm_linux_platform_setup(); + if (global_opt.state_file) { + int i_obj_type; + + for (i_obj_type = 0; i_obj_type < (int) G_N_ELEMENTS(dump_obj_types); i_obj_type++) { + NMPObjectType obj_type = dump_obj_types[i_obj_type].obj_type; + + g_signal_connect(NM_PLATFORM_GET, + nmp_class_from_type(obj_type)->signal_type, + G_CALLBACK(_dump_state_platform_cb), + NULL); + } + } + mptcp_addr_dump(NM_PLATFORM_GET); + _dump_state(NM_PLATFORM_GET, global_opt.state_file); + if (global_opt.persist) g_main_loop_run(loop); g_main_loop_unref(loop); + g_signal_handlers_disconnect_by_func(NM_PLATFORM_GET, + G_CALLBACK(_dump_state_platform_cb), + NULL); + g_object_unref(NM_PLATFORM_GET); + return EXIT_SUCCESS; } diff --git a/src/core/platform/tests/test-address.c b/src/core/platform/tests/test-address.c index 700891e8..0bce00c4 100644 --- a/src/core/platform/tests/test-address.c +++ b/src/core/platform/tests/test-address.c @@ -118,7 +118,7 @@ test_ip4_address_general(void) addresses = nmtstp_platform_ip4_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addresses); g_assert_cmpint(addresses->len, ==, 1); - address = &g_array_index(addresses, NMPlatformIP4Address, 0); + address = &nm_g_array_first(addresses, NMPlatformIP4Address); g_assert_cmpint(address->ifindex, ==, ifindex); g_assert_cmphex(address->address, ==, addr); g_assert_cmphex(address->peer_address, ==, addr); @@ -193,7 +193,7 @@ test_ip6_address_general(void) addresses = nmtstp_platform_ip6_address_get_all(NM_PLATFORM_GET, ifindex); g_assert(addresses); g_assert_cmpint(addresses->len, ==, 1); - address = &g_array_index(addresses, NMPlatformIP6Address, 0); + address = &nm_g_array_first(addresses, NMPlatformIP6Address); g_assert_cmpint(address->ifindex, ==, ifindex); g_assert(!memcmp(&address->address, &addr, sizeof(addr))); g_assert_cmpint(address->plen, ==, IP6_PLEN); @@ -453,7 +453,7 @@ _nmtstp_init_tests(int *argc, char ***argv) void _nmtstp_setup_tests(void) { -#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, FALSE) +#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, 1, FALSE) add_test_func("/address/ipv4/general", test_ip4_address_general); add_test_func("/address/ipv6/general", test_ip6_address_general); diff --git a/src/core/platform/tests/test-cleanup.c b/src/core/platform/tests/test-cleanup.c index 2198e921..139a0280 100644 --- a/src/core/platform/tests/test-cleanup.c +++ b/src/core/platform/tests/test-cleanup.c @@ -63,7 +63,7 @@ test_cleanup_internal(void) nm_platform_process_events(NM_PLATFORM_GET); } addrs = nmtstp_platform_ip6_address_get_all(NM_PLATFORM_GET, ifindex); - if (addrs->len == 1 && (a = &g_array_index(addrs, NMPlatformIP6Address, 0)) + if (addrs->len == 1 && (a = &nm_g_array_first(addrs, NMPlatformIP6Address)) && IN6_IS_ADDR_LINKLOCAL(&a->address)) break; }); @@ -73,7 +73,7 @@ test_cleanup_internal(void) addr4, plen4, addr4, - nm_platform_ip4_broadcast_address_create(addr4, plen4), + nm_ip4_addr_get_broadcast_address(addr4, plen4), lifetime, preferred, 0, diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index b5bb1232..571fedfe 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -15,6 +15,7 @@ #include <linux/rtnetlink.h> #include "n-acd/src/n-acd.h" +#include "libnm-platform/nm-platform-utils.h" #define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)" #define SIGNAL_DATA_ARG(data) \ @@ -22,8 +23,60 @@ (data)->ifname ? " ifname '" : "", (data)->ifname ?: "", (data)->ifname ? "'" : "", \ (data)->received_count -int NMTSTP_ENV1_IFINDEX = -1; -int NMTSTP_ENV1_EX = -1; +int NMTSTP_ENV1_IFINDEXES[]; + +const char *const NMTSTP_ENV1_DEVICE_NAME[] = { + "nm-test-device0", + "nm-test-device1", +}; + +int NMTSTP_ENV1_EX = -1; + +/*****************************************************************************/ + +typedef struct { + const char *module_name; + + NMLinkType iftype; + + /* These modules create additional interfaces, like + * "gre0" for "ip_gre" module. + * + * - actually some modules create multiple interfaces, like "ip_gre" + * creating "gre0", "gretap0", "erspan0". + * - if already an interface with such name exist, kernel would create + * names like "gre1" or "gretap1". We don't care for that, because + * we run in our own namespace and we control which interfaces are there. + * We wouldn't create an interface with such a conflicting name. + * + * Anyway. This is the name of *one* of the interfaces that the module would + * create. */ + const char *ifname; + + /* This only gets set, if iftype is NM_LINK_TYPE_UNKNOWN. It corresponds to + * NMPlatformLink.kind. */ + const char *ifkind; + +} IPTunnelModInfo; + +#define INF(_module_name, _iftype, _ifname, ...) \ + { \ + .module_name = ""_module_name, .iftype = _iftype, .ifname = ""_ifname, __VA_ARGS__ \ + } + +static const IPTunnelModInfo ip_tunnel_mod_infos[] = { + INF("ip_gre", NM_LINK_TYPE_GRE, "gre0"), + INF("ip_gre", NM_LINK_TYPE_GRETAP, "gretap0"), + INF("ip_gre", NM_LINK_TYPE_UNKNOWN, "erspan0", .ifkind = "erspan"), + INF("ipip", NM_LINK_TYPE_IPIP, "tunl0"), + INF("ip6_tunnel", NM_LINK_TYPE_IP6TNL, "ip6tnl0"), + INF("ip6_gre", NM_LINK_TYPE_IP6GRE, "ip6gre0"), + INF("sit", NM_LINK_TYPE_SIT, "sit0"), + INF("ip_vti", NM_LINK_TYPE_VTI, "ip_vti0"), + INF("ip6_vti", NM_LINK_TYPE_VTI6, "ip6_vti0"), +}; + +#undef INF /*****************************************************************************/ @@ -218,13 +271,13 @@ _nmtstp_platform_ip_addresses_assert(const char *filename, } if (!addr_bin->found) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; g_error("%s:%d: IPv%c address %s was not found on ifindex %d", filename, lineno, nm_utils_addr_family_to_char(addr_bin->addr_family), - nm_utils_inet_ntop(addr_bin->addr_family, &addr_bin->addr, sbuf), + nm_inet_ntop(addr_bin->addr_family, &addr_bin->addr, sbuf), ifindex); } } @@ -583,7 +636,7 @@ _nmtstp_assert_ip4_route_exists(const char *file, r = _ip4_route_get(platform, ifindex, network, plen, metric, tos, &c); if (c != c_exists && c_exists != -1) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf[NM_INET_ADDRSTRLEN]; NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER g_error("[%s:%u] %s(): The ip4 route %s/%d metric %u tos %u shall exist %u times, but " @@ -591,7 +644,7 @@ _nmtstp_assert_ip4_route_exists(const char *file, file, line, func, - _nm_utils_inet4_ntop(network, sbuf), + nm_inet4_ntop(network, sbuf), plen, metric, tos, @@ -683,8 +736,8 @@ _nmtstp_assert_ip6_route_exists(const char *file, r = _ip6_route_get(platform, ifindex, network, plen, metric, src, src_plen, &c); if (c != c_exists && c_exists != -1) { - char s_src[NM_UTILS_INET_ADDRSTRLEN]; - char s_network[NM_UTILS_INET_ADDRSTRLEN]; + char s_src[NM_INET_ADDRSTRLEN]; + char s_network[NM_INET_ADDRSTRLEN]; NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER g_error("[%s:%u] %s(): The ip6 route %s/%d metric %u src %s/%d shall exist %u times, but " @@ -692,10 +745,10 @@ _nmtstp_assert_ip6_route_exists(const char *file, file, line, func, - _nm_utils_inet6_ntop(network, s_network), + nm_inet6_ntop(network, s_network), plen, metric, - _nm_utils_inet6_ntop(src, s_src), + nm_inet6_ntop(src, s_src), src_plen, c_exists, c); @@ -739,6 +792,642 @@ nmtstp_run_command(const char *format, ...) /*****************************************************************************/ +static int +_assert_platform_sort_objs(gconstpointer ptr_a, gconstpointer ptr_b) +{ + const NMPObject *a = *((const NMPObject *const *) ptr_a); + const NMPObject *b = *((const NMPObject *const *) ptr_b); + + g_assert(NMP_OBJECT_IS_VALID(a)); + g_assert(NMP_OBJECT_IS_VALID(b)); + g_assert(NMP_OBJECT_GET_TYPE(a) == NMP_OBJECT_GET_TYPE(b)); + + NM_CMP_RETURN(nmp_object_id_cmp(a, b)); + g_assert_not_reached(); + return 0; +} + +static void +_assert_platform_printarr(NMPObjectType obj_type, GPtrArray *arr1, GPtrArray *arr2) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + guint i; + + _LOGT("compare arrays of %s. In cache %u entries, fetched %u entries", + NMP_OBJECT_TYPE_NAME(obj_type), + nm_g_ptr_array_len(arr1), + nm_g_ptr_array_len(arr2)); + + for (i = 0; i < nm_g_ptr_array_len(arr1); i++) { + _LOGT("cache[%u] %s", + i, + nmp_object_to_string(arr1->pdata[i], NMP_OBJECT_TO_STRING_ALL, sbuf, sizeof(sbuf))); + } + for (i = 0; i < nm_g_ptr_array_len(arr2); i++) { + _LOGT("fetch[%u] %s", + i, + nmp_object_to_string(arr2->pdata[i], NMP_OBJECT_TO_STRING_ALL, sbuf, sizeof(sbuf))); + } + + switch (obj_type) { + case NMP_OBJECT_TYPE_LINK: + nmtstp_run_command("ip -d link"); + break; + case NMP_OBJECT_TYPE_IP4_ADDRESS: + nmtstp_run_command("ip -d -4 address"); + break; + case NMP_OBJECT_TYPE_IP6_ADDRESS: + nmtstp_run_command("ip -d -6 address"); + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + nmtstp_run_command("ip -d -4 route show table all"); + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + nmtstp_run_command("ip -d -6 route show table all"); + break; + default: + g_assert_not_reached(); + break; + } +} + +static gboolean +_assert_platform_normalize_all(GPtrArray *arr) +{ + guint i; + gboolean normalized = FALSE; + + for (i = 0; i < nm_g_ptr_array_len(arr); i++) { + const NMPObject **ptr = (gpointer) &arr->pdata[i]; + nm_auto_nmpobj NMPObject *new = NULL; + gboolean skip = FALSE; + + switch (NMP_OBJECT_GET_TYPE(*ptr)) { + case NMP_OBJECT_TYPE_LINK: + { + const NMPlatformLink *link = NMP_OBJECT_CAST_LINK(*ptr); + + if (nmtstp_link_is_iptunnel_special(link)) { + /* These are special interfaces for the ip tunnel modules, like + * "gre0" created by the "ip_gre" module. + * + * These interfaces can appear at any moment, when the module + * gets loaded (by anybody on the host). We might want to avoid + * that by calling nmtstp_ensure_module(), but it's worse. + * Kernel does not send correct RTM_NEWLINK events when those + * interfaces get created. So the cache content based on the + * events will differ from a new load from a dump. + * + * We need to ignore those interfaces. */ + skip = TRUE; + } else if (link->type == NM_LINK_TYPE_UNKNOWN) { + /* The link type is not detected. This might be a generated + * interface like nmtstp_link_is_iptunnel_special(), but for + * kernel modules that we don't know about. Ignore them too. */ + skip = TRUE; + } + + if (!skip) { + new = nmp_object_clone(*ptr, FALSE); + new->link.rx_packets = 0; + new->link.rx_bytes = 0; + new->link.tx_packets = 0; + new->link.tx_bytes = 0; + } + if (nmp_object_ref_set(ptr, new)) + normalized = TRUE; + break; + } + default: + break; + } + } + + while (g_ptr_array_remove(arr, NULL)) { + /* Remove NULL values. */ + normalized = TRUE; + } + + return normalized; +} + +static gboolean +_assert_platform_compare_arr(NMPObjectType obj_type, + const char *detail_type, + GPtrArray *arr1, + GPtrArray *arr2, + gboolean normalized, + gboolean share_multi_idx, + gboolean do_assert) +{ + const NMPClass *obj_class = nmp_class_from_type(obj_type); + char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; + char sbuf2[NM_UTILS_TO_STRING_BUFFER_SIZE]; + int idx; + int idx_pointer_comp = -1; + +#define _fail_msg(do_assert, ...) \ + G_STMT_START \ + { \ + if (do_assert) { \ + g_error(__VA_ARGS__); \ + } else { \ + _LOGW(__VA_ARGS__); \ + return FALSE; \ + } \ + } \ + G_STMT_END + + for (idx = 0; TRUE; idx++) { + if (nm_g_ptr_array_len(arr1) == idx && nm_g_ptr_array_len(arr2) == idx) + break; + if (idx >= nm_g_ptr_array_len(arr1)) { + _assert_platform_printarr(obj_type, arr1, arr2); + _fail_msg(do_assert, + "Comparing %s (%s) for platform fails. Platform now shows entry #%u which is " + "not in the cache but expected %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr2->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1))); + } + if (idx >= nm_g_ptr_array_len(arr2)) { + _assert_platform_printarr(obj_type, arr1, arr2); + _fail_msg( + do_assert, + "Comparing %s (%s) for platform fails. Platform has no more entry #%u which is " + "still in the cache as %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr1->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1))); + } + if (!nmp_object_equal(arr1->pdata[idx], arr2->pdata[idx])) { + _assert_platform_printarr(obj_type, arr1, arr2); + _fail_msg(do_assert, + "Comparing %s (%s) for platform fails. Platform entry #%u is now %s but in " + "cache is %s", + obj_class->obj_type_name, + detail_type, + idx, + nmp_object_to_string(arr2->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1)), + nmp_object_to_string(arr1->pdata[idx], + NMP_OBJECT_TO_STRING_ALL, + sbuf2, + sizeof(sbuf2))); + } + + if (!normalized && (share_multi_idx != (arr1->pdata[idx] == arr2->pdata[idx])) + && idx_pointer_comp == -1) + idx_pointer_comp = idx; + } + + if (idx_pointer_comp != -1) { + _assert_platform_printarr(obj_type, arr1, arr2); + _fail_msg(do_assert, + "Comparing %s (%s) for platform fails for pointer comparison. Platform entry " + "#%u is now %s but in cache is %s", + obj_class->obj_type_name, + detail_type, + idx_pointer_comp, + nmp_object_to_string(arr2->pdata[idx_pointer_comp], + NMP_OBJECT_TO_STRING_ALL, + sbuf1, + sizeof(sbuf1)), + nmp_object_to_string(arr1->pdata[idx_pointer_comp], + NMP_OBJECT_TO_STRING_ALL, + sbuf2, + sizeof(sbuf2))); + } + + return TRUE; +} + +/*****************************************************************************/ + +gboolean +nmtstp_link_is_iptunnel_special(const NMPlatformLink *link) +{ + int i; + + g_assert(link); + + /* These interfaces are autogenerated when loading the ip tunnel + * modules. For example, loading "ip_gre" results in interfaces + * "gre0", "gretap0", "erspan0". + * + * Actually, if the interface names are already taken ("gre0" already + * exists), it will create "gre1" and so on. We don't care about that, + * because in our test's netns that is not happening. */ + + for (i = 0; i < (int) G_N_ELEMENTS(ip_tunnel_mod_infos); i++) { + const IPTunnelModInfo *module_info = &ip_tunnel_mod_infos[i]; + + if (module_info->iftype != link->type) + continue; + if (!nm_streq(module_info->ifname, link->name)) + continue; + if (module_info->ifkind && !nm_streq(module_info->ifkind, link->kind)) + continue; + + return TRUE; + } + + return FALSE; +} + +/*****************************************************************************/ + +gboolean +nmtstp_ensure_module(const char *module_name) +{ + /* using iproute2 seems to fail sometimes? Force use of platform code. */ + const int EX = 0; + gs_free char *test_ifname = NULL; + const NMPlatformLink *link; + static int module_state[G_N_ELEMENTS(ip_tunnel_mod_infos)] = {0}; + int i_module_info; + const IPTunnelModInfo *module_info = NULL; + int i; + int ifindex; + gboolean result; + + if (!module_name) { + result = TRUE; + for (i = 0; i < (int) G_N_ELEMENTS(ip_tunnel_mod_infos); i++) { + if (!nmtstp_ensure_module(ip_tunnel_mod_infos[i].module_name)) + result = FALSE; + } + return result; + } + + for (i_module_info = 0; i_module_info < (int) G_N_ELEMENTS(ip_tunnel_mod_infos); + i_module_info++) { + if (nm_streq(module_name, ip_tunnel_mod_infos[i_module_info].module_name)) { + module_info = &ip_tunnel_mod_infos[i_module_info]; + break; + } + } + if (!module_info) + g_error("%s:%d: Module name \"%s\" not implemented!", __FILE__, __LINE__, module_name); + + test_ifname = g_strdup_printf("nm-mod-%s", module_info->ifname); + g_assert(nm_utils_ifname_valid_kernel(test_ifname, NULL)); + +again: + i = g_atomic_int_get(&module_state[i_module_info]); + if (i != 0) + return i > 0; + + /* When tunnel modules get loaded, then interfaces like "gre0", "gretap0" + * and "erspan0" (for "ip_gre" module) appear. For other modules, the interfaces + * are named differently. Of course, unless those interface name are already taken, + * in which case it will create "gre1", etc). So ugly. + * + * Anyway. as we run unit tests in parallel (`make check -j`), another + * test might just load the module just now, which results in the creation of + * those interfaces in our current namespace. That can break the test. + */ + + link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, test_ifname, module_info->iftype); + g_assert(!link); + + link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, module_info->ifname, module_info->iftype); + if (link) { + g_assert(nmtstp_link_is_iptunnel_special(link)); + /* An interface with this name exists. While technically this could not be the interface + * generated by the kernel module, in our test netns we can assume that it is. This is + * good enough. */ + result = TRUE; + goto out; + } + + /* Try to load the module. It probably won't work, because we don't have permissions. + * Ignore any failure. */ + nmp_utils_modprobe(NULL, TRUE, module_info->module_name, NULL); + + if (nm_streq(module_name, "ip_gre")) { + link = nmtstp_link_gre_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkGre){ + .local = nmtst_inet4_from_string("192.168.233.204"), + .remote = nmtst_inet4_from_string("172.168.10.25"), + .parent_ifindex = 0, + .ttl = 174, + .tos = 37, + .path_mtu_discovery = TRUE, + })); + } else if (nm_streq(module_name, "ipip")) { + link = nmtstp_link_ipip_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkIpIp){ + .local = nmtst_inet4_from_string("1.2.3.4"), + .remote = nmtst_inet4_from_string("5.6.7.8"), + .parent_ifindex = 0, + .tos = 32, + .path_mtu_discovery = FALSE, + })); + } else if (nm_streq(module_name, "ip6_tunnel")) { + link = nmtstp_link_ip6tnl_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkIp6Tnl){ + .local = nmtst_inet6_from_string("fd01::15"), + .remote = nmtst_inet6_from_string("fd01::16"), + .tclass = 20, + .encap_limit = 6, + .flow_label = 1337, + .proto = IPPROTO_IPV6, + })); + } else if (nm_streq(module_name, "ip6_gre")) { + link = nmtstp_link_ip6gre_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkIp6Tnl){ + .local = nmtst_inet6_from_string("fd01::42"), + .remote = nmtst_inet6_from_string("fd01::aaaa"), + .tclass = 21, + .flow_label = 1338, + .is_gre = TRUE, + })); + } else if (nm_streq(module_name, "sit")) { + link = nmtstp_link_sit_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkSit){ + .local = nmtst_inet4_from_string("192.168.200.1"), + .remote = nmtst_inet4_from_string("172.25.100.14"), + .ttl = 0, + .tos = 31, + .path_mtu_discovery = FALSE, + })); + } else if (nm_streq(module_name, "ip_vti")) { + link = nmtstp_link_vti_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkVti){ + .local = nmtst_inet4_from_string("192.168.212.204"), + .remote = nmtst_inet4_from_string("172.168.11.25"), + .ikey = 12, + .okey = 13, + })); + } else if (nm_streq(module_name, "ip6_vti")) { + link = nmtstp_link_vti6_add(NULL, + EX, + test_ifname, + &((const NMPlatformLnkVti6){ + .local = nmtst_inet6_from_string("fd01::1"), + .remote = nmtst_inet6_from_string("fd02::2"), + .ikey = 13, + .okey = 14, + })); + } else + g_error("%s:%d: Module name \"%s\" not implemented!", __FILE__, __LINE__, module_name); + + if (!link) { + /* We might be unable to add the interface, if the kernel module does not exist. + * Be graceful about that. */ + ifindex = 0; + g_assert(!nmtstp_link_get_typed(NM_PLATFORM_GET, 0, test_ifname, module_info->iftype)); + g_assert( + !nmtstp_link_get_typed(NM_PLATFORM_GET, 0, module_info->ifname, module_info->iftype)); + } else { + ifindex = link->ifindex; + + g_assert(link); + g_assert( + link + == nmtstp_link_get_typed(NM_PLATFORM_GET, ifindex, test_ifname, module_info->iftype)); + + nmtstp_link_delete(NULL, -1, link->ifindex, test_ifname, TRUE); + + link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, module_info->ifname, module_info->iftype); + g_assert(nmtstp_link_is_iptunnel_special(link)); + } + + result = ifindex > 0 ? 1 : -1; + +out: + if (!g_atomic_int_compare_and_exchange(&module_state[i_module_info], 0, result)) + goto again; + + if (!result) { + /* The function aims to be graceful about missing kernel modules. */ + + /* g_error("Failure to ensure module \"%s\"", module_name); */ + } + + return result; +} + +gboolean +nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolean do_assert) +{ + static const NMPObjectType obj_types[] = { + NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP6_ADDRESS, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_LINK, + }; + gboolean obj_type_flags_all = (obj_type_flags == 0u); + gs_unref_object NMPlatform *platform2 = NULL; + int i_obj_types; + gboolean share_multi_idx = nmtst_get_rand_bool(); + + /* This test creates a new NMLinuxPlatform instance. This will fill + * the cache with a new dump. + * + * Then it compares the content with @platform and checks that they + * agree. This tests that @platform cache is consistent, as it was + * updated based on netlink events. */ + + g_assert(NM_IS_LINUX_PLATFORM(platform)); + + _LOGD("assert-platform: start"); + + nm_platform_process_events(platform); + + platform2 = nm_linux_platform_new(share_multi_idx ? nm_platform_get_multi_idx(platform) : NULL, + TRUE, + nmtst_get_rand_bool(), + nmtst_get_rand_bool()); + g_assert(NM_IS_LINUX_PLATFORM(platform2)); + + for (i_obj_types = 0; i_obj_types < (int) G_N_ELEMENTS(obj_types); i_obj_types++) { + const NMPObjectType obj_type = obj_types[i_obj_types]; + const guint32 i_obj_type_flags = nmp_object_type_to_flags(obj_type); + gs_unref_ptrarray GPtrArray *arr1 = NULL; + gs_unref_ptrarray GPtrArray *arr2 = NULL; + NMPLookup lookup; + gboolean check_unordered = TRUE; + guint idx; + gboolean normalized; + + if (!obj_type_flags_all) { + if (!NM_FLAGS_ANY(obj_type_flags, i_obj_type_flags)) + continue; + obj_type_flags = NM_FLAGS_UNSET(obj_type_flags, i_obj_type_flags); + } + + nmp_lookup_init_obj_type(&lookup, obj_type); + + arr1 = nm_platform_lookup_clone(platform, &lookup, NULL, NULL) ?: g_ptr_array_new(); + arr2 = nm_platform_lookup_clone(platform2, &lookup, NULL, NULL) ?: g_ptr_array_new(); + + normalized = _assert_platform_normalize_all(arr1); + normalized = _assert_platform_normalize_all(arr2); + + if (check_unordered) { + /* We need to sort the two lists. */ + g_ptr_array_sort(arr1, _assert_platform_sort_objs); + g_ptr_array_sort(arr2, _assert_platform_sort_objs); + } + + if (!_assert_platform_compare_arr(obj_type, + "main", + arr1, + arr2, + normalized, + share_multi_idx, + do_assert)) + return FALSE; + + if (NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) { + /* For routes, the WEAK_ID needs to be sorted and match the expected order. Check that. */ + g_assert(!normalized); + for (idx = 0; idx < nm_g_ptr_array_len(arr1); idx++) { + const NMPObject *obj1 = arr1->pdata[idx]; + const NMPObject *obj2 = arr2->pdata[idx]; + gs_unref_ptrarray GPtrArray *arr1b = NULL; + gs_unref_ptrarray GPtrArray *arr2b = NULL; + gs_unref_ptrarray GPtrArray *arr1b_sorted = NULL; + gs_unref_ptrarray GPtrArray *arr2b_sorted = NULL; + guint found_obj1 = 0; + guint found_obj2 = 0; + guint i; + + nmp_lookup_init_route_by_weak_id(&lookup, obj1); + arr1b = + nm_platform_lookup_clone(platform, &lookup, NULL, NULL) ?: g_ptr_array_new(); + g_assert_cmpint(arr1b->len, >, 0u); + + nmp_lookup_init_route_by_weak_id(&lookup, obj2); + arr2b = + nm_platform_lookup_clone(platform2, &lookup, NULL, NULL) ?: g_ptr_array_new(); + g_assert_cmpint(arr2b->len, ==, arr1b->len); + + /* First check that the lists agree, if we sort them. The list of + * weak-ids was supposed to honor the sort order from `ip route show`, + * but as that is not the case (see blow), first check whether at + * least the same routes are in the list (with wrong sort order). */ + arr1b_sorted = nm_g_ptr_array_new_clone(arr1b, NULL, NULL, NULL); + arr2b_sorted = nm_g_ptr_array_new_clone(arr2b, NULL, NULL, NULL); + g_ptr_array_sort(arr1b_sorted, _assert_platform_sort_objs); + g_ptr_array_sort(arr2b_sorted, _assert_platform_sort_objs); + if (!_assert_platform_compare_arr(obj_type, + "weak-id-sorted", + arr1b_sorted, + arr2b_sorted, + normalized, + share_multi_idx, + do_assert)) + return FALSE; + + if (obj_type == NMP_OBJECT_TYPE_IP6_ROUTE) { + /* For IPv6, the weak-ids are actually not sorted correctly. + * This is because IPv6 multihop/ECMP routes get split into + * multiple objects, and we don't get this right. + * + * This may be a bug. But we probably don't rely on this + * anymore, because the weak-id were used to find which + * route got replaced with `NLM_F_REPLACE`, but that anyway + * doesn't work. We now always request a new dump. */ + } else if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE) { + /* For IPv4, it also does not reliably always work. This may + * be a bug we want to fix. For now, ignore the check. + * + * a) Kernel can wrongly allow to configure the same route twice. + * That means, the same route is visible in `ip route` output, + * meaning, it would be added twice to the platform cache. + * At least due to that problem, may the weak-id not be properly sorted. + * See https://bugzilla.redhat.com/show_bug.cgi?id=2165720 which is + * a bug of kernel allowing to configure the exact same route twice. + * + * b) See https://bugzilla.redhat.com/show_bug.cgi?id=2162315 which is + * a bug where kernel does allow to configure single-hop routes that differ by + * their next-hop weight, but on the netlink API those routes look the same. + * + * Due to a) and b), the platform cache may contain only one instance + * of a route, which is visible more than once in `ip route` output. + * This merging of different routes causes problems, and it also means + * that the RTM_NEWROUTE events are wrongly interpreted and the weak-id + * is not properly sorted. + */ + } else { + /* Assert that also the original, not-sorted lists agree. */ + if (!_assert_platform_compare_arr(obj_type, + "weak-id", + arr1b, + arr2b, + normalized, + share_multi_idx, + do_assert)) + return FALSE; + } + + for (i = 0; i < arr1b->len; i++) { + if (arr1b->pdata[i] == obj1) + found_obj1++; + if (arr2b->pdata[i] == obj2) + found_obj2++; + } + + g_assert_cmpint(found_obj1, ==, 1u); + g_assert_cmpint(found_obj2, ==, 1u); + } + } + } + + g_clear_object(&platform2); + + _LOGD("assert-platform: done"); + + g_assert_cmpint(obj_type_flags, ==, 0u); + + return TRUE; +} + +void +nmtstp_check_platform(NMPlatform *platform, guint32 obj_type_flags) +{ + if (!nmtstp_check_platform_full(platform, obj_type_flags, FALSE)) { + /* It's unclear why this failure sometimes happens. It happens + * on gitlab-ci on Ubuntu/Debian(??). + * + * Retrying shortly after seems to avoid it. */ + g_usleep(20 * 1000); + nm_platform_process_events(platform); + nmtstp_run_command("ip route"); + nm_platform_process_events(platform); + + nmtstp_check_platform_full(platform, obj_type_flags, TRUE); + } +} + +/*****************************************************************************/ + typedef struct { GMainLoop *loop; guint signal_counts; @@ -1036,7 +1725,7 @@ nmtstp_ip_address_assert_lifetime(const NMPlatformIPAddress *addr, static void _ip_address_add(NMPlatform *platform, - gboolean external_command, + int external_command, gboolean is_v4, int ifindex, const NMIPAddr *address, @@ -1058,8 +1747,8 @@ _ip_address_add(NMPlatform *platform, gs_free char *s_valid = NULL; gs_free char *s_preferred = NULL; gs_free char *s_label = NULL; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; + char b1[NM_INET_ADDRSTRLEN]; + char b2[NM_INET_ADDRSTRLEN]; ifname = nm_platform_link_get_name(platform, ifindex); g_assert(ifname); @@ -1072,18 +1761,18 @@ _ip_address_add(NMPlatform *platform, s_label = g_strdup_printf("%s:%s", ifname, label); if (is_v4) { - char s_peer[NM_UTILS_INET_ADDRSTRLEN + 50]; + char s_peer[NM_INET_ADDRSTRLEN + 50]; g_assert(flags == 0); if (peer_address->addr4 != address->addr4 || nmtst_get_rand_uint32() % 2) { /* If the peer is the same as the local address, we can omit it. The result should be identical */ - nm_sprintf_buf(s_peer, " peer %s", _nm_utils_inet4_ntop(peer_address->addr4, b2)); + nm_sprintf_buf(s_peer, " peer %s", nm_inet4_ntop(peer_address->addr4, b2)); } else s_peer[0] = '\0'; nmtstp_run_command_check("ip address change %s%s/%d dev %s%s%s%s", - _nm_utils_inet4_ntop(address->addr4, b1), + nm_inet4_ntop(address->addr4, b1), s_peer, plen, ifname, @@ -1096,10 +1785,10 @@ _ip_address_add(NMPlatform *platform, /* flags not implemented (yet) */ g_assert(flags == 0); nmtstp_run_command_check("ip address change %s%s%s/%d dev %s%s%s%s", - _nm_utils_inet6_ntop(&address->addr6, b1), + nm_inet6_ntop(&address->addr6, b1), !IN6_IS_ADDR_UNSPECIFIED(&peer_address->addr6) ? " peer " : "", !IN6_IS_ADDR_UNSPECIFIED(&peer_address->addr6) - ? _nm_utils_inet6_ntop(&peer_address->addr6, b2) + ? nm_inet6_ntop(&peer_address->addr6, b2) : "", plen, ifname, @@ -1188,7 +1877,7 @@ _ip_address_add(NMPlatform *platform, void nmtstp_ip4_address_add(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, in_addr_t address, int plen, @@ -1202,9 +1891,13 @@ nmtstp_ip4_address_add(NMPlatform *platform, external_command, TRUE, ifindex, - (NMIPAddr *) &address, + &((NMIPAddr){ + .addr4 = address, + }), plen, - (NMIPAddr *) &peer_address, + &((NMIPAddr){ + .addr4 = peer_address, + }), lifetime, preferred, flags, @@ -1213,7 +1906,7 @@ nmtstp_ip4_address_add(NMPlatform *platform, void nmtstp_ip6_address_add(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, struct in6_addr address, int plen, @@ -1257,8 +1950,8 @@ nmtstp_ip4_route_add(NMPlatform *platform, route.metric = metric; route.mss = mss; - g_assert( - NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_REPLACE, &route))); + g_assert(NMTST_NM_ERR_SUCCESS( + nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_REPLACE, &route, NULL))); } void @@ -1291,7 +1984,7 @@ nmtstp_ip6_route_add(NMPlatform *platform, static void _ip_address_del(NMPlatform *platform, - gboolean external_command, + int external_command, gboolean is_v4, int ifindex, const NMIPAddr *address, @@ -1306,8 +1999,8 @@ _ip_address_del(NMPlatform *platform, if (external_command) { const char *ifname; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; + char b1[NM_INET_ADDRSTRLEN]; + char b2[NM_INET_ADDRSTRLEN]; int success; gboolean had_address; @@ -1325,18 +2018,17 @@ _ip_address_del(NMPlatform *platform, had_address = !!nm_platform_ip6_address_get(platform, ifindex, &address->addr6); if (is_v4) { - success = nmtstp_run_command("ip address delete %s%s%s/%d dev %s", - _nm_utils_inet4_ntop(address->addr4, b1), - peer_address->addr4 != address->addr4 ? " peer " : "", - peer_address->addr4 != address->addr4 - ? _nm_utils_inet4_ntop(peer_address->addr4, b2) - : "", - plen, - ifname); + success = nmtstp_run_command( + "ip address delete %s%s%s/%d dev %s", + nm_inet4_ntop(address->addr4, b1), + peer_address->addr4 != address->addr4 ? " peer " : "", + peer_address->addr4 != address->addr4 ? nm_inet4_ntop(peer_address->addr4, b2) : "", + plen, + ifname); } else { g_assert(!peer_address); success = nmtstp_run_command("ip address delete %s/%d dev %s", - _nm_utils_inet6_ntop(&address->addr6, b1), + nm_inet6_ntop(&address->addr6, b1), plen, ifname); } @@ -1391,7 +2083,7 @@ _ip_address_del(NMPlatform *platform, void nmtstp_ip4_address_del(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, in_addr_t address, int plen, @@ -1408,7 +2100,7 @@ nmtstp_ip4_address_del(NMPlatform *platform, void nmtstp_ip6_address_del(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, struct in6_addr address, int plen) @@ -1478,7 +2170,7 @@ nmtstp_link_bridge_normalize_jiffies_time(const NMPlatformLnkBridge *requested, const NMPlatformLink * nmtstp_link_bridge_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkBridge *lnk) { @@ -1633,10 +2325,7 @@ nmtstp_link_bridge_add(NMPlatform *platform, return pllink; } const NMPlatformLink * -nmtstp_link_veth_add(NMPlatform *platform, - gboolean external_command, - const char *name, - const char *peer) +nmtstp_link_veth_add(NMPlatform *platform, int external_command, const char *name, const char *peer) { const NMPlatformLink *pllink = NULL; gboolean success = FALSE; @@ -1681,7 +2370,7 @@ again: } const NMPlatformLink * -nmtstp_link_dummy_add(NMPlatform *platform, gboolean external_command, const char *name) +nmtstp_link_dummy_add(NMPlatform *platform, int external_command, const char *name) { const NMPlatformLink *pllink = NULL; gboolean success; @@ -1706,7 +2395,7 @@ nmtstp_link_dummy_add(NMPlatform *platform, gboolean external_command, const cha const NMPlatformLink * nmtstp_link_gre_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkGre *lnk) { @@ -1734,13 +2423,13 @@ nmtstp_link_gre_add(NMPlatform *platform, obj = lnk->is_tap ? "link" : "tunnel"; type = lnk->is_tap ? "type gretap" : "mode gre"; - success = !nmtstp_run_command("ip %s add %s %s %s local %s remote %s ttl %u tos %02x %s", + success = !nmtstp_run_command("ip %s add %s %s%s%s local %s remote %s ttl %u tos %02x %s", obj, name, type, - dev ?: "", - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), + NM_PRINT_FMT_QUOTED2(dev, " ", dev, ""), + nm_inet4_ntop(lnk->local, b1), + nm_inet4_ntop(lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); @@ -1757,14 +2446,14 @@ nmtstp_link_gre_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_ip6tnl_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk) { const NMPlatformLink *pllink = NULL; gboolean success; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; + char b1[NM_INET_ADDRSTRLEN]; + char b2[NM_INET_ADDRSTRLEN]; char encap[20]; char tclass[20]; gboolean encap_ignore; @@ -1800,13 +2489,13 @@ nmtstp_link_ip6tnl_add(NMPlatform *platform, tclass_inherit = NM_FLAGS_HAS(lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); success = !nmtstp_run_command( - "ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %s encaplimit %s " + "ip -6 tunnel add %s mode %s%s%s local %s remote %s ttl %u tclass %s encaplimit %s " "flowlabel %x", name, mode, - dev, - _nm_utils_inet6_ntop(&lnk->local, b1), - _nm_utils_inet6_ntop(&lnk->remote, b2), + NM_PRINT_FMT_QUOTED2(dev, " ", dev, ""), + nm_inet6_ntop(&lnk->local, b1), + nm_inet6_ntop(&lnk->remote, b2), lnk->ttl, tclass_inherit ? "inherit" : nm_sprintf_buf(tclass, "%02x", lnk->tclass), encap_ignore ? "none" : nm_sprintf_buf(encap, "%u", lnk->encap_limit), @@ -1823,14 +2512,14 @@ nmtstp_link_ip6tnl_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_ip6gre_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk) { const NMPlatformLink *pllink = NULL; gboolean success; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; + char b1[NM_INET_ADDRSTRLEN]; + char b2[NM_INET_ADDRSTRLEN]; char tclass[20]; gboolean tclass_inherit; @@ -1851,12 +2540,12 @@ nmtstp_link_ip6gre_add(NMPlatform *platform, tclass_inherit = NM_FLAGS_HAS(lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); success = !nmtstp_run_command( - "ip link add %s type %s %s local %s remote %s ttl %u tclass %s flowlabel %x", + "ip link add %s type %s%s%s local %s remote %s ttl %u tclass %s flowlabel %x", name, lnk->is_tap ? "ip6gretap" : "ip6gre", - dev, - _nm_utils_inet6_ntop(&lnk->local, b1), - _nm_utils_inet6_ntop(&lnk->remote, b2), + NM_PRINT_FMT_QUOTED2(dev, " ", dev, ""), + nm_inet6_ntop(&lnk->local, b1), + nm_inet6_ntop(&lnk->remote, b2), lnk->ttl, tclass_inherit ? "inherit" : nm_sprintf_buf(tclass, "%02x", lnk->tclass), lnk->flow_label); @@ -1882,7 +2571,7 @@ nmtstp_link_ip6gre_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_ipip_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIpIp *lnk) { @@ -1905,11 +2594,11 @@ nmtstp_link_ipip_add(NMPlatform *platform, g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); success = !nmtstp_run_command( - "ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s", + "ip tunnel add %s mode ipip%s%s local %s remote %s ttl %u tos %02x %s", name, - dev, - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), + NM_PRINT_FMT_QUOTED2(dev, " ", dev, ""), + nm_inet4_ntop(lnk->local, b1), + nm_inet4_ntop(lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); @@ -1925,7 +2614,7 @@ nmtstp_link_ipip_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_macvlan_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, int parent, const NMPlatformLnkMacvlan *lnk) @@ -1945,10 +2634,10 @@ nmtstp_link_macvlan_add(NMPlatform *platform, if (external_command) { const char *dev; char *modes[] = { - [MACVLAN_MODE_BRIDGE] = "bridge", - [MACVLAN_MODE_VEPA] = "vepa", - [MACVLAN_MODE_PRIVATE] = "private", - [MACVLAN_MODE_PASSTHRU] = "passthru", + [MACVLAN_MODE_BRIDGE] = "bridge", + [MACVLAN_MODE_VEPA] = "vepa", + [MACVLAN_MODE_PRIVATE] = "private", + [MACVLAN_MODE_PASSTHRU] = "passthru", }; dev = nm_platform_link_get_name(platform, parent); @@ -1974,7 +2663,7 @@ nmtstp_link_macvlan_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_sit_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkSit *lnk) { @@ -2004,8 +2693,8 @@ nmtstp_link_sit_add(NMPlatform *platform, !nmtstp_run_command("ip tunnel add %s mode sit%s local %s remote %s ttl %u tos %02x %s", name, dev, - _nm_utils_inet4_ntop(lnk->local, b1), - _nm_utils_inet4_ntop(lnk->remote, b2), + nm_inet4_ntop(lnk->local, b1), + nm_inet4_ntop(lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); @@ -2021,7 +2710,7 @@ nmtstp_link_sit_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_tun_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkTun *lnk, int *out_fd) @@ -2085,9 +2774,135 @@ nmtstp_link_tun_add(NMPlatform *platform, } const NMPlatformLink * -nmtstp_link_vrf_add(NMPlatform *platform, +nmtstp_link_vlan_add(NMPlatform *platform, + int external_command, + const char *name, + int parent, + const NMPlatformLnkVlan *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + + g_assert(nm_utils_ifname_valid_kernel(name, NULL)); + + external_command = nmtstp_run_command_check_external(external_command); + + _init_platform(&platform, external_command); + + if (external_command) { + const char *dev; + + dev = nm_platform_link_get_name(platform, parent); + g_assert(dev); + g_assert(NM_IN_SET(lnk->protocol, ETH_P_8021Q, ETH_P_8021AD)); + + success = !nmtstp_run_command( + "ip link add name %s link %s type vlan id %hu protocol %s%s%s%s%s", + name, + dev, + lnk->id, + lnk->protocol == ETH_P_8021Q ? "802.1Q" : "802.1ad", + !(lnk->flags & _NM_VLAN_FLAG_REORDER_HEADERS) ? " reorder_hdr off" : "", + (lnk->flags & _NM_VLAN_FLAG_GVRP) ? " gvrp on" : "", + (lnk->flags & _NM_VLAN_FLAG_MVRP) ? " mvrp on" : "", + (lnk->flags & _NM_VLAN_FLAG_LOOSE_BINDING) ? " loose_binding on" : ""); + if (success) + pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VLAN, 100); + } else + success = + NMTST_NM_ERR_SUCCESS(nm_platform_link_vlan_add(platform, name, parent, lnk, &pllink)); + + _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_VLAN); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_vti_add(NMPlatform *platform, gboolean external_command, const char *name, + const NMPlatformLnkVti *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char b1[INET_ADDRSTRLEN]; + char b2[INET_ADDRSTRLEN]; + + g_assert(nm_utils_ifname_valid_kernel(name, NULL)); + external_command = nmtstp_run_command_check_external(external_command); + _init_platform(&platform, external_command); + g_assert(lnk->fwmark == 0); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = + g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); + + success = + !nmtstp_run_command("ip link add %s type vti %s local %s remote %s ikey %u okey %u", + name, + dev ?: "", + nm_inet4_ntop(lnk->local, b1), + nm_inet4_ntop(lnk->remote, b2), + lnk->ikey, + lnk->okey); + if (success) + pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VTI, 100); + } else + success = NMTST_NM_ERR_SUCCESS(nm_platform_link_vti_add(platform, name, lnk, &pllink)); + + _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_VTI); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_vti6_add(NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVti6 *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char b1[INET6_ADDRSTRLEN]; + char b2[INET6_ADDRSTRLEN]; + + g_assert(nm_utils_ifname_valid_kernel(name, NULL)); + external_command = nmtstp_run_command_check_external(external_command); + _init_platform(&platform, external_command); + g_assert(lnk->fwmark == 0); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = + g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); + + success = + !nmtstp_run_command("ip link add %s type vti6 %s local %s remote %s ikey %u okey %u", + name, + dev ?: "", + nm_inet6_ntop(&lnk->local, b1), + nm_inet6_ntop(&lnk->remote, b2), + lnk->ikey, + lnk->okey); + if (success) + pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VTI6, 100); + } else + success = NMTST_NM_ERR_SUCCESS(nm_platform_link_vti6_add(platform, name, lnk, &pllink)); + + _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_VTI6); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_vrf_add(NMPlatform *platform, + int external_command, + const char *name, const NMPlatformLnkVrf *lnk, gboolean *out_not_supported) { @@ -2123,7 +2938,7 @@ nmtstp_link_vrf_add(NMPlatform *platform, const NMPlatformLink * nmtstp_link_vxlan_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkVxlan *lnk) { @@ -2139,24 +2954,24 @@ nmtstp_link_vxlan_add(NMPlatform *platform, if (external_command) { gs_free char *dev = NULL; - char local[NM_UTILS_INET_ADDRSTRLEN]; - char group[NM_UTILS_INET_ADDRSTRLEN]; + char local[NM_INET_ADDRSTRLEN]; + char group[NM_INET_ADDRSTRLEN]; if (lnk->parent_ifindex) dev = g_strdup_printf("dev %s", nm_platform_link_get_name(platform, lnk->parent_ifindex)); if (lnk->local) - _nm_utils_inet4_ntop(lnk->local, local); + nm_inet4_ntop(lnk->local, local); else if (memcmp(&lnk->local6, &in6addr_any, sizeof(in6addr_any))) - _nm_utils_inet6_ntop(&lnk->local6, local); + nm_inet6_ntop(&lnk->local6, local); else local[0] = '\0'; if (lnk->group) - _nm_utils_inet4_ntop(lnk->group, group); + nm_inet4_ntop(lnk->group, group); else if (memcmp(&lnk->group6, &in6addr_any, sizeof(in6addr_any))) - _nm_utils_inet6_ntop(&lnk->group6, group); + nm_inet6_ntop(&lnk->group6, group); else group[0] = '\0'; @@ -2239,7 +3054,7 @@ nmtstp_link_get(NMPlatform *platform, int ifindex, const char *name) void nmtstp_link_delete(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, const char *name, gboolean require_exist) @@ -2291,7 +3106,7 @@ nmtstp_link_delete(NMPlatform *platform, /*****************************************************************************/ void -nmtstp_link_set_updown(NMPlatform *platform, gboolean external_command, int ifindex, gboolean up) +nmtstp_link_set_updown(NMPlatform *platform, int external_command, int ifindex, gboolean up) { const NMPlatformLink *plink; gint64 end_time; @@ -2739,7 +3554,7 @@ nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_a NAcdProbe *probe = NULL; int fd; int r; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; g_assert_cmpint(ifindex, >, 0); g_assert(mac_addr); @@ -2780,7 +3595,7 @@ nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_a NM_HASH_OBFUSCATE_PTR(defender), ifindex, NM_ETHER_ADDR_FORMAT_VAL(mac_addr), - _nm_utils_inet4_ntop(ip_addr, sbuf_addr)); + nm_inet4_ntop(ip_addr, sbuf_addr)); n_acd_probe_set_userdata(defender->probe, defender); diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index da30b0ed..2802d8fd 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -18,8 +18,6 @@ #include "nm-test-utils-core.h" -#define DEVICE_NAME "nm-test-device" - /*****************************************************************************/ #define nmtstp_normalize_jiffies_time(requested_value, kernel_value) \ @@ -141,6 +139,13 @@ int nmtstp_run_command(const char *format, ...) _nm_printf(1, 2); /*****************************************************************************/ +gboolean +nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolean do_assert); + +void nmtstp_check_platform(NMPlatform *platform, guint32 obj_type_flags); + +/*****************************************************************************/ + guint nmtstp_wait_for_signal(NMPlatform *platform, gint64 timeout_msec); guint nmtstp_wait_for_signal_until(NMPlatform *platform, gint64 until_ms); const NMPlatformLink *nmtstp_wait_for_link(NMPlatform *platform, @@ -261,7 +266,7 @@ void nmtstp_ip_address_assert_lifetime(const NMPlatformIPAddress *addr, guint32 expected_preferred); void nmtstp_ip4_address_add(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, in_addr_t address, int plen, @@ -271,7 +276,7 @@ void nmtstp_ip4_address_add(NMPlatform *platform, guint32 flags, const char *label); void nmtstp_ip6_address_add(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, struct in6_addr address, int plen, @@ -280,13 +285,13 @@ void nmtstp_ip6_address_add(NMPlatform *platform, guint32 preferred, guint32 flags); void nmtstp_ip4_address_del(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); void nmtstp_ip6_address_del(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, struct in6_addr address, int plen); @@ -452,8 +457,7 @@ const NMPlatformLink *nmtstp_link_get(NMPlatform *platform, int ifindex, const c gboolean nmtstp_kernel_support_get(NMPlatformKernelSupportType type); -void -nmtstp_link_set_updown(NMPlatform *platform, gboolean external_command, int ifindex, gboolean up); +void nmtstp_link_set_updown(NMPlatform *platform, int external_command, int ifindex, gboolean up); const NMPlatformLnkBridge * nmtstp_link_bridge_normalize_jiffies_time(const NMPlatformLnkBridge *requested, @@ -461,61 +465,78 @@ nmtstp_link_bridge_normalize_jiffies_time(const NMPlatformLnkBridge *requested, NMPlatformLnkBridge *dst); const NMPlatformLink *nmtstp_link_bridge_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkBridge *lnk); const NMPlatformLink *nmtstp_link_veth_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const char *peer); const NMPlatformLink * -nmtstp_link_dummy_add(NMPlatform *platform, gboolean external_command, const char *name); +nmtstp_link_dummy_add(NMPlatform *platform, int external_command, const char *name); const NMPlatformLink *nmtstp_link_gre_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkGre *lnk); const NMPlatformLink *nmtstp_link_ip6tnl_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk); const NMPlatformLink *nmtstp_link_ip6gre_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk); const NMPlatformLink *nmtstp_link_ipip_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkIpIp *lnk); const NMPlatformLink *nmtstp_link_macvlan_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, int parent, const NMPlatformLnkMacvlan *lnk); const NMPlatformLink *nmtstp_link_sit_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkSit *lnk); const NMPlatformLink *nmtstp_link_tun_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkTun *lnk, int *out_fd); -const NMPlatformLink *nmtstp_link_vrf_add(NMPlatform *platform, +const NMPlatformLink *nmtstp_link_vlan_add(NMPlatform *platform, + int external_command, + const char *name, + int parent, + const NMPlatformLnkVlan *lnk); +const NMPlatformLink *nmtstp_link_vti_add(NMPlatform *platform, gboolean external_command, const char *name, + const NMPlatformLnkVti *lnk); +const NMPlatformLink *nmtstp_link_vti6_add(NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVti6 *lnk); +const NMPlatformLink *nmtstp_link_vrf_add(NMPlatform *platform, + int external_command, + const char *name, const NMPlatformLnkVrf *lnk, gboolean *out_not_supported); const NMPlatformLink *nmtstp_link_vxlan_add(NMPlatform *platform, - gboolean external_command, + int external_command, const char *name, const NMPlatformLnkVxlan *lnk); void nmtstp_link_delete(NMPlatform *platform, - gboolean external_command, + int external_command, int ifindex, const char *name, gboolean require_exist); +gboolean nmtstp_link_is_iptunnel_special(const NMPlatformLink *link); + +gboolean nmtstp_ensure_module(const char *module_name); + /*****************************************************************************/ #define nmtst_object_new_mptcp_addr(...) \ @@ -523,36 +544,47 @@ void nmtstp_link_delete(NMPlatform *platform, /*****************************************************************************/ -extern int NMTSTP_ENV1_IFINDEX; +extern int NMTSTP_ENV1_IFINDEXES[2]; +extern const char *const NMTSTP_ENV1_DEVICE_NAME[G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)]; + +#define DEVICE_NAME "nm-test-device0" +#define NMTSTP_ENV1_IFINDEX (NMTSTP_ENV1_IFINDEXES[0]) + extern int NMTSTP_ENV1_EX; static inline void _nmtstp_env1_wrapper_setup(const NmtstTestData *test_data) { - int *p_ifindex; + int *p_ifindexes; + gpointer p_n_ifaces; gpointer p_ifup; - - nmtst_test_data_unpack(test_data, &p_ifindex, NULL, NULL, NULL, &p_ifup); - - g_assert(p_ifindex && *p_ifindex == -1); + int n_ifaces; + int i; _LOGT("TEST[%s]: setup", test_data->testpath); - nmtstp_link_delete(NM_PLATFORM_GET, -1, -1, DEVICE_NAME, FALSE); + nmtst_test_data_unpack(test_data, &p_ifindexes, &p_n_ifaces, NULL, NULL, NULL, &p_ifup); - g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(NM_PLATFORM_GET, DEVICE_NAME, NULL))); + n_ifaces = GPOINTER_TO_UINT(p_n_ifaces); + g_assert_cmpint(n_ifaces, >=, 1); + g_assert_cmpint(n_ifaces, <=, (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)); - *p_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); - g_assert_cmpint(*p_ifindex, >, 0); - g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, -1); + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) { + g_assert_cmpint(NMTSTP_ENV1_IFINDEXES[i], ==, 0); + g_assert_cmpint(p_ifindexes[i], ==, 0); + } - if (GPOINTER_TO_INT(p_ifup)) - g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, *p_ifindex, IFF_UP, TRUE) >= 0); + for (i = 0; i < n_ifaces; i++) { + p_ifindexes[i] = nmtstp_link_dummy_add(NULL, -1, NMTSTP_ENV1_DEVICE_NAME[i])->ifindex; + if (GPOINTER_TO_INT(p_ifup)) + nmtstp_link_set_updown(NULL, -1, p_ifindexes[i], TRUE); + } nm_platform_process_events(NM_PLATFORM_GET); - NMTSTP_ENV1_IFINDEX = *p_ifindex; - NMTSTP_ENV1_EX = nmtstp_run_command_check_external_global(); + for (i = 0; i < n_ifaces; i++) + NMTSTP_ENV1_IFINDEXES[i] = p_ifindexes[i]; + NMTSTP_ENV1_EX = nmtstp_run_command_check_external_global(); } static inline void @@ -563,7 +595,7 @@ _nmtstp_env1_wrapper_run(gconstpointer user_data) GTestFunc test_func; gconstpointer d; - nmtst_test_data_unpack(test_data, NULL, &test_func, &test_func_data, &d, NULL); + nmtst_test_data_unpack(test_data, NULL, NULL, &test_func, &test_func_data, &d, NULL); _LOGT("TEST[%s]: run", test_data->testpath); if (test_func) @@ -575,55 +607,73 @@ _nmtstp_env1_wrapper_run(gconstpointer user_data) static inline void _nmtstp_env1_wrapper_teardown(const NmtstTestData *test_data) { - int *p_ifindex; + int *p_ifindexes; + gpointer p_n_ifaces; + int n_ifaces; + int i; - nmtst_test_data_unpack(test_data, &p_ifindex, NULL, NULL, NULL, NULL); + _LOGT("TEST[%s]: teardown", test_data->testpath); - g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, *p_ifindex); - NMTSTP_ENV1_IFINDEX = -1; + nmtst_test_data_unpack(test_data, &p_ifindexes, &p_n_ifaces, NULL, NULL, NULL, NULL); - _LOGT("TEST[%s]: teardown", test_data->testpath); + n_ifaces = GPOINTER_TO_UINT(p_n_ifaces); + g_assert_cmpint(n_ifaces, >=, 1); + g_assert_cmpint(n_ifaces, <=, (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)); + + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) { + if (i < n_ifaces) + g_assert_cmpint(p_ifindexes[i], >, 0); + else + g_assert_cmpint(p_ifindexes[i], ==, 0); + g_assert_cmpint(NMTSTP_ENV1_IFINDEXES[i], ==, p_ifindexes[i]); + NMTSTP_ENV1_IFINDEXES[i] = 0; + } - g_assert_cmpint(*p_ifindex, ==, nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME)); - g_assert(nm_platform_link_delete(NM_PLATFORM_GET, *p_ifindex)); + for (i = 0; i < n_ifaces; i++) + nmtstp_link_delete(NULL, -1, p_ifindexes[i], NMTSTP_ENV1_DEVICE_NAME[i], TRUE); nm_platform_process_events(NM_PLATFORM_GET); _LOGT("TEST[%s]: finished", test_data->testpath); - *p_ifindex = -1; + for (i = 0; i < (int) G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES); i++) + p_ifindexes[i] = 0; } /* add test function, that set's up a particular environment, consisting * of a dummy device with ifindex NMTSTP_ENV1_IFINDEX. */ -#define _nmtstp_env1_add_test_func_full(testpath, test_func, test_data_func, arg, ifup) \ - nmtst_add_test_func_full(testpath, \ - _nmtstp_env1_wrapper_run, \ - _nmtstp_env1_wrapper_setup, \ - _nmtstp_env1_wrapper_teardown, \ - ({ \ - static int _ifindex = -1; \ - &_ifindex; \ - }), \ - ({ \ - GTestFunc _test_func = (test_func); \ - _test_func; \ - }), \ - ({ \ - GTestDataFunc _test_func = (test_data_func); \ - _test_func; \ - }), \ - (arg), \ - ({ \ - gboolean _ifup = (ifup); \ - GINT_TO_POINTER(_ifup); \ +#define _nmtstp_env1_add_test_func_full(testpath, test_func, test_data_func, arg, n_ifaces, ifup) \ + nmtst_add_test_func_full(testpath, \ + _nmtstp_env1_wrapper_run, \ + _nmtstp_env1_wrapper_setup, \ + _nmtstp_env1_wrapper_teardown, \ + ({ \ + static int _ifindexes[G_N_ELEMENTS(NMTSTP_ENV1_IFINDEXES)] = {0}; \ + _ifindexes; \ + }), \ + ({ \ + guint _n_ifaces = (n_ifaces); \ + GUINT_TO_POINTER(_n_ifaces); \ + }), \ + ({ \ + GTestFunc _test_func = (test_func); \ + _test_func; \ + }), \ + ({ \ + GTestDataFunc _test_func = (test_data_func); \ + _test_func; \ + }), \ + (arg), \ + ({ \ + gboolean _ifup = (ifup); \ + GINT_TO_POINTER(!!_ifup); \ })) -#define nmtstp_env1_add_test_func_data(testpath, test_func, arg, ifup) \ - _nmtstp_env1_add_test_func_full(testpath, NULL, test_func, arg, ifup) +#define nmtstp_env1_add_test_func_data(testpath, test_func, arg, n_ifaces, ifup) \ + _nmtstp_env1_add_test_func_full(testpath, NULL, test_func, arg, n_ifaces, ifup) -#define nmtstp_env1_add_test_func(testpath, test_func, ifup) \ - _nmtstp_env1_add_test_func_full(testpath, test_func, NULL, NULL, ifup) +#define nmtstp_env1_add_test_func(testpath, test_func, n_ifaces, ifup) \ + _nmtstp_env1_add_test_func_full(testpath, test_func, NULL, NULL, n_ifaces, ifup) /*****************************************************************************/ diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index b72bcb65..cc1ec6d1 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -161,8 +161,14 @@ software_add(NMLinkType link_type, const char *name) accept_signals(parent_changed, 1, 2); free_signal(parent_changed); - return NMTST_NM_ERR_SUCCESS( - nm_platform_link_vlan_add(NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL)); + return NMTST_NM_ERR_SUCCESS(nm_platform_link_vlan_add(NM_PLATFORM_GET, + name, + parent_ifindex, + &((NMPlatformLnkVlan){ + .id = VLAN_ID, + .protocol = ETH_P_8021Q, + }), + NULL)); } } default: @@ -1183,7 +1189,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) for (i = 0; i < num_peers; i++) { NMPWireGuardPeer peer; - char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_addr[NM_INET_ADDRSTRLEN]; NMSockAddrUnion endpoint; guint i_allowed_ips, n_allowed_ips; NMPWireGuardAllowedIP *allowed_ips; @@ -1203,8 +1209,8 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) .in6 = { .sin6_family = AF_INET6, - .sin6_addr = *nmtst_inet6_from_string( - nm_sprintf_buf(s_addr, "a:b:c:e::1:%d", i)), + .sin6_addr = + nmtst_inet6_from_string(nm_sprintf_buf(s_addr, "a:b:c:e::1:%d", i)), .sin6_port = htons(16000 + i), }, }; @@ -1225,7 +1231,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) nm_sprintf_buf(s_addr, "10.%u.%u.0", i, i_allowed_ips)); aip->mask = 32 - (i_allowed_ips % 8); } else { - aip->addr.addr6 = *nmtst_inet6_from_string( + aip->addr.addr6 = nmtst_inet6_from_string( nm_sprintf_buf(s_addr, "a:d:f:%02x:%02x::", i, i_allowed_ips)); aip->mask = 128 - (i_allowed_ips % 10); } @@ -1250,7 +1256,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) r = nm_platform_link_wireguard_change(platform, ifindex, &lnk_wireguard, - (const NMPWireGuardPeer *) peers->data, + nm_g_array_first_p(peers, const NMPWireGuardPeer), NULL, peers->len, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY @@ -1280,8 +1286,11 @@ test_software_detect(gconstpointer user_data) const gboolean ext = test_data->external_command; NMPlatformLnkBridge lnk_bridge = {}; NMPlatformLnkTun lnk_tun; - NMPlatformLnkGre lnk_gre = {}; - nm_auto_close int tun_fd = -1; + NMPlatformLnkGre lnk_gre = {}; + NMPlatformLnkVti lnk_vti = {}; + NMPlatformLnkVti6 lnk_vti6 = {}; + nm_auto_close int tun_fd = -1; + gboolean module_loaded; nmtstp_run_command_check("ip link add %s type dummy", PARENT_NAME); ifindex_parent = @@ -1296,24 +1305,24 @@ test_software_detect(gconstpointer user_data) lnk_bridge.ageing_time = 2200; lnk_bridge.stp_state = TRUE; lnk_bridge.priority = 22; - lnk_bridge.vlan_protocol = 0x8100; + lnk_bridge.vlan_protocol = ETH_P_8021Q; lnk_bridge.vlan_stats_enabled = nmtstp_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED) ? TRUE : FALSE; - lnk_bridge.group_fwd_mask = 8; - lnk_bridge.group_addr = (NMEtherAddr){{0x01, 0x80, 0xC2, 0x00, 0x00, 0x08}}; - lnk_bridge.mcast_snooping = TRUE; - lnk_bridge.mcast_router = 1; - lnk_bridge.mcast_query_use_ifaddr = TRUE; - lnk_bridge.mcast_querier = TRUE; - lnk_bridge.mcast_hash_max = 1024; - lnk_bridge.mcast_last_member_count = 2; - lnk_bridge.mcast_startup_query_count = 3; - lnk_bridge.mcast_last_member_interval = 5000; - lnk_bridge.mcast_membership_interval = 25000; - lnk_bridge.mcast_querier_interval = 26000; - lnk_bridge.mcast_query_interval = 12000; + lnk_bridge.group_fwd_mask = 8; + lnk_bridge.group_addr = NM_ETHER_ADDR_INIT(0x01, 0x80, 0xC2, 0x00, 0x00, 0x08); + lnk_bridge.mcast_snooping = TRUE; + lnk_bridge.mcast_router = 1; + lnk_bridge.mcast_query_use_ifaddr = TRUE; + lnk_bridge.mcast_querier = TRUE; + lnk_bridge.mcast_hash_max = 1024; + lnk_bridge.mcast_last_member_count = 2; + lnk_bridge.mcast_startup_query_count = 3; + lnk_bridge.mcast_last_member_interval = 5000; + lnk_bridge.mcast_membership_interval = 25000; + lnk_bridge.mcast_querier_interval = 26000; + lnk_bridge.mcast_query_interval = 12000; lnk_bridge.mcast_query_response_interval = 5200; lnk_bridge.mcast_startup_query_interval = 3000; @@ -1322,8 +1331,7 @@ test_software_detect(gconstpointer user_data) break; case NM_LINK_TYPE_GRE: - { - gboolean gracefully_skip = FALSE; + module_loaded = nmtstp_ensure_module("ip_gre"); lnk_gre.local = nmtst_inet4_from_string("192.168.233.204"); lnk_gre.remote = nmtst_inet4_from_string("172.168.10.25"); @@ -1332,13 +1340,8 @@ test_software_detect(gconstpointer user_data) lnk_gre.tos = 37; lnk_gre.path_mtu_discovery = TRUE; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "gre0")) { - /* Seems that the ip_gre module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0; - } - if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip( "Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)"); goto out_delete_parent; @@ -1346,10 +1349,9 @@ test_software_detect(gconstpointer user_data) g_error("Failed adding GRE tunnel"); } break; - } + case NM_LINK_TYPE_GRETAP: - { - gboolean gracefully_skip = FALSE; + module_loaded = nmtstp_ensure_module("ip_gre"); lnk_gre.local = nmtst_inet4_from_string("192.168.1.133"); lnk_gre.remote = nmtst_inet4_from_string("172.168.101.2"); @@ -1359,13 +1361,8 @@ test_software_detect(gconstpointer user_data) lnk_gre.path_mtu_discovery = FALSE; lnk_gre.is_tap = TRUE; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "gretap0")) { - /* Seems that the ip_gre module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0; - } - if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip("Cannot create gretap tunnel because of missing ip_gre module " "(modprobe ip_gre)"); goto out_delete_parent; @@ -1373,16 +1370,12 @@ test_software_detect(gconstpointer user_data) g_error("Failed adding GRETAP tunnel"); } break; - } + case NM_LINK_TYPE_IPIP: { - NMPlatformLnkIpIp lnk_ipip = {}; - gboolean gracefully_skip = FALSE; + NMPlatformLnkIpIp lnk_ipip = {}; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "tunl0")) { - /* Seems that the ipip module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ipip", NULL) != 0; - } + module_loaded = nmtstp_ensure_module("ipip"); lnk_ipip.local = nmtst_inet4_from_string("1.2.3.4"); lnk_ipip.remote = nmtst_inet4_from_string("5.6.7.8"); @@ -1391,7 +1384,7 @@ test_software_detect(gconstpointer user_data) lnk_ipip.path_mtu_discovery = FALSE; if (!nmtstp_link_ipip_add(NULL, ext, DEVICE_NAME, &lnk_ipip)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip( "Cannot create ipip tunnel because of missing ipip module (modprobe ipip)"); goto out_delete_parent; @@ -1400,20 +1393,17 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6TNL: { - NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - gboolean gracefully_skip = FALSE; + NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6tnl0")) { - /* Seems that the ip6_tunnel module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_tunnel", NULL) != 0; - } + module_loaded = nmtstp_ensure_module("ip6_tunnel"); switch (test_data->test_mode) { case 0: - lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::15"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::16"); + lnk_ip6tnl.local = nmtst_inet6_from_string("fd01::15"); + lnk_ip6tnl.remote = nmtst_inet6_from_string("fd01::16"); lnk_ip6tnl.parent_ifindex = ifindex_parent; lnk_ip6tnl.tclass = 20; lnk_ip6tnl.encap_limit = 6; @@ -1421,8 +1411,8 @@ test_software_detect(gconstpointer user_data) lnk_ip6tnl.proto = IPPROTO_IPV6; break; case 1: - lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::17"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::18"); + lnk_ip6tnl.local = nmtst_inet6_from_string("fd01::17"); + lnk_ip6tnl.remote = nmtst_inet6_from_string("fd01::18"); lnk_ip6tnl.parent_ifindex = ifindex_parent; lnk_ip6tnl.tclass = 0; lnk_ip6tnl.encap_limit = 0; @@ -1433,7 +1423,7 @@ test_software_detect(gconstpointer user_data) } if (!nmtstp_link_ip6tnl_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip("Cannot create ip6tnl tunnel because of missing ip6_tunnel module " "(modprobe ip6_tunnel)"); goto out_delete_parent; @@ -1442,25 +1432,22 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRE: { - NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - gboolean gracefully_skip = FALSE; + NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) { - /* Seems that the ip6_tunnel module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; - } + module_loaded = nmtstp_ensure_module("ip6_gre"); - lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::42"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string("fd01::aaaa"); + lnk_ip6tnl.local = nmtst_inet6_from_string("fd01::42"); + lnk_ip6tnl.remote = nmtst_inet6_from_string("fd01::aaaa"); lnk_ip6tnl.parent_ifindex = ifindex_parent; lnk_ip6tnl.tclass = 21; lnk_ip6tnl.flow_label = 1338; lnk_ip6tnl.is_gre = TRUE; if (!nmtstp_link_ip6gre_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip("Cannot create ip6gre tunnel because of missing ip6_gre module " "(modprobe ip6_gre)"); goto out_delete_parent; @@ -1469,18 +1456,15 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRETAP: { - NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - gboolean gracefully_skip = FALSE; + NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) { - /* Seems that the ip6_tunnel module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; - } + module_loaded = nmtstp_ensure_module("ip6_gre"); - lnk_ip6tnl.local = *nmtst_inet6_from_string("fe80::abcd"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string("fc01::bbbb"); + lnk_ip6tnl.local = nmtst_inet6_from_string("fe80::abcd"); + lnk_ip6tnl.remote = nmtst_inet6_from_string("fc01::bbbb"); lnk_ip6tnl.parent_ifindex = ifindex_parent; lnk_ip6tnl.ttl = 10; lnk_ip6tnl.tclass = 22; @@ -1489,7 +1473,7 @@ test_software_detect(gconstpointer user_data) lnk_ip6tnl.is_tap = TRUE; if (!nmtstp_link_ip6gre_add(NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip("Cannot create ip6gretap tunnel because of missing ip6_gre module " "(modprobe ip6_gre)"); goto out_delete_parent; @@ -1498,6 +1482,7 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_MACVLAN: { NMPlatformLnkMacvlan lnk_macvlan = {}; @@ -1531,6 +1516,7 @@ test_software_detect(gconstpointer user_data) g_error("Failed adding MACVLAN interface"); break; } + case NM_LINK_TYPE_MACVTAP: { NMPlatformLnkMacvlan lnk_macvtap = {}; @@ -1543,10 +1529,12 @@ test_software_detect(gconstpointer user_data) g_error("Failed adding MACVTAP interface"); break; } + case NM_LINK_TYPE_SIT: { - NMPlatformLnkSit lnk_sit = {}; - gboolean gracefully_skip = FALSE; + NMPlatformLnkSit lnk_sit = {}; + + module_loaded = nmtstp_ensure_module("sit"); lnk_sit.local = nmtst_inet4_from_string("192.168.200.1"); lnk_sit.remote = nmtst_inet4_from_string("172.25.100.14"); @@ -1555,13 +1543,8 @@ test_software_detect(gconstpointer user_data) lnk_sit.tos = 31; lnk_sit.path_mtu_discovery = FALSE; - if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "sit0")) { - /* Seems that the sit module is not loaded... try to load it. */ - gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "sit", NULL) != 0; - } - if (!nmtstp_link_sit_add(NULL, ext, DEVICE_NAME, &lnk_sit)) { - if (gracefully_skip) { + if (!module_loaded) { g_test_skip( "Cannot create sit tunnel because of missing sit module (modprobe sit)"); goto out_delete_parent; @@ -1570,11 +1553,31 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_VLAN: - nmtstp_run_command_check("ip link add name %s link %s type vlan id 1242", - DEVICE_NAME, - PARENT_NAME); + { + NMPlatformLnkVlan lnk_vlan = {}; + + switch (test_data->test_mode) { + case 0: + lnk_vlan.id = 1242; + lnk_vlan.protocol = ETH_P_8021Q; + lnk_vlan.flags = _NM_VLAN_FLAG_REORDER_HEADERS; + break; + case 1: + lnk_vlan.id = 4094; + lnk_vlan.protocol = ETH_P_8021AD; + lnk_vlan.flags = _NM_VLAN_FLAG_GVRP | _NM_VLAN_FLAG_MVRP; + break; + default: + nm_assert_not_reached(); + } + + if (!nmtstp_link_vlan_add(NULL, ext, DEVICE_NAME, ifindex_parent, &lnk_vlan)) + g_error("Failed adding VLAN interface"); break; + } + case NM_LINK_TYPE_VRF: { NMPlatformLnkVrf lnk_vrf = {}; @@ -1591,6 +1594,45 @@ test_software_detect(gconstpointer user_data) } break; } + + case NM_LINK_TYPE_VTI: + module_loaded = nmtstp_ensure_module("ip_vti"); + + lnk_vti.local = nmtst_inet4_from_string("192.168.212.204"); + lnk_vti.remote = nmtst_inet4_from_string("172.168.11.25"); + lnk_vti.parent_ifindex = ifindex_parent; + lnk_vti.ikey = 12; + lnk_vti.okey = 13; + + if (!nmtstp_link_vti_add(NULL, ext, DEVICE_NAME, &lnk_vti)) { + if (!module_loaded) { + g_test_skip( + "Cannot create vti tunnel because of missing vti module (modprobe ip_vti)"); + goto out_delete_parent; + } + g_error("Failed adding VTI tunnel"); + } + break; + + case NM_LINK_TYPE_VTI6: + module_loaded = nmtstp_ensure_module("ip6_vti"); + + lnk_vti6.local = nmtst_inet6_from_string("fd01::1"); + lnk_vti6.remote = nmtst_inet6_from_string("fd02::2"); + lnk_vti6.parent_ifindex = ifindex_parent; + lnk_vti6.ikey = 13; + lnk_vti6.okey = 14; + + if (!nmtstp_link_vti6_add(NULL, ext, DEVICE_NAME, &lnk_vti6)) { + if (!module_loaded) { + g_test_skip( + "Cannot create vti6 tunnel because of missing vti module (modprobe ip_vti)"); + goto out_delete_parent; + } + g_error("Failed adding VTI6 tunnel"); + } + break; + case NM_LINK_TYPE_VXLAN: { NMPlatformLnkVxlan lnk_vxlan = {}; @@ -1608,8 +1650,8 @@ test_software_detect(gconstpointer user_data) case 1: lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, PARENT_NAME); lnk_vxlan.id = 11214423; - lnk_vxlan.local6 = *nmtst_inet6_from_string("1:2:3:4:334:23::23"); - lnk_vxlan.group6 = *nmtst_inet6_from_string("ff0e::115"); + lnk_vxlan.local6 = nmtst_inet6_from_string("1:2:3:4:334:23::23"); + lnk_vxlan.group6 = nmtst_inet6_from_string("ff0e::115"); lnk_vxlan.ttl = 32; lnk_vxlan.dst_port = 57412; lnk_vxlan.src_port_min = 1000; @@ -1622,6 +1664,7 @@ test_software_detect(gconstpointer user_data) g_assert(nmtstp_link_vxlan_add(NULL, ext, DEVICE_NAME, &lnk_vxlan)); break; } + case NM_LINK_TYPE_TUN: { gboolean owner_valid = nmtst_get_rand_bool(); @@ -1656,6 +1699,7 @@ test_software_detect(gconstpointer user_data) (!lnk_tun.persist || nmtst_get_rand_bool()) ? &tun_fd : NULL)); break; } + case NM_LINK_TYPE_WIREGUARD: { const NMPlatformLink *link; @@ -1727,7 +1771,7 @@ test_software_detect(gconstpointer user_data) g_assert_cmpint(plnk->ageing_time, ==, lnk_bridge_norm->ageing_time); g_assert_cmpint(plnk->stp_state, ==, TRUE); g_assert_cmpint(plnk->priority, ==, 22); - g_assert_cmpint(plnk->vlan_protocol, ==, 0x8100); + g_assert_cmpint(plnk->vlan_protocol, ==, ETH_P_8021Q); g_assert_cmpint(plnk->vlan_stats_enabled, ==, lnk_bridge_norm->vlan_stats_enabled); g_assert_cmpint(plnk->group_fwd_mask, ==, 8); g_assert_cmpint(plnk->mcast_snooping, ==, TRUE); @@ -1910,7 +1954,19 @@ test_software_detect(gconstpointer user_data) const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; g_assert(plnk == nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint(plnk->id, ==, 1242); + + switch (test_data->test_mode) { + case 0: + g_assert_cmpint(plnk->id, ==, 1242); + g_assert_cmpint(plnk->protocol, ==, ETH_P_8021Q); + g_assert_cmpint(plnk->flags, ==, _NM_VLAN_FLAG_REORDER_HEADERS); + break; + case 1: + g_assert_cmpint(plnk->id, ==, 4094); + g_assert_cmpint(plnk->protocol, ==, ETH_P_8021AD); + g_assert_cmpint(plnk->flags, ==, _NM_VLAN_FLAG_GVRP | _NM_VLAN_FLAG_MVRP); + break; + } break; } case NM_LINK_TYPE_VRF: @@ -1921,6 +1977,22 @@ test_software_detect(gconstpointer user_data) g_assert_cmpint(plnk->table, ==, 9876); break; } + case NM_LINK_TYPE_VTI: + { + const NMPlatformLnkVti *plnk = &lnk->lnk_vti; + + g_assert(plnk == nm_platform_link_get_lnk_vti(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_lnk_vti_cmp(plnk, &lnk_vti) == 0); + break; + } + case NM_LINK_TYPE_VTI6: + { + const NMPlatformLnkVti6 *plnk = &lnk->lnk_vti6; + + g_assert(plnk == nm_platform_link_get_lnk_vti6(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_lnk_vti6_cmp(plnk, &lnk_vti6) == 0); + break; + } case NM_LINK_TYPE_VXLAN: { const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan; @@ -2511,7 +2583,7 @@ test_create_many_links_do(guint n_devices) if (EX == 2) nmtstp_run_command_check("ip link delete %s", name); else - nmtstp_link_delete(NULL, EX, g_array_index(ifindexes, int, i), name, TRUE); + nmtstp_link_delete(NULL, EX, nm_g_array_index(ifindexes, int, i), name, TRUE); } _LOGI(">>> process events after deleting devices..."); @@ -2754,7 +2826,7 @@ _test_netns_create_platform(void) netns = nmp_netns_new(); g_assert(NMP_IS_NETNS(netns)); - platform = nm_linux_platform_new(TRUE, TRUE, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); g_assert(NM_IS_LINUX_PLATFORM(platform)); nmp_netns_pop(netns); @@ -2843,7 +2915,7 @@ test_netns_general(gpointer fixture, gconstpointer test_data) if (_check_sysctl_skip()) return; - platform_1 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platform_1 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platform_2 = _test_netns_create_platform(); /* add some dummy devices. The "other-*" devices are there to bump the ifindex */ @@ -2971,7 +3043,7 @@ test_netns_set_netns(gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); @@ -3070,7 +3142,7 @@ test_netns_push(gpointer fixture, gconstpointer test_data) if (_check_sysctl_skip()) return; - pl[0].platform = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + pl[0].platform = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); pl[1].platform = platform_1 = _test_netns_create_platform(); pl[2].platform = platform_2 = _test_netns_create_platform(); @@ -3217,7 +3289,7 @@ test_netns_bind_to_path(gpointer fixture, gconstpointer test_data) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); @@ -3382,7 +3454,7 @@ test_sysctl_netns_switch(void) if (_test_netns_check_skip()) return; - platforms[0] = platform_0 = nm_linux_platform_new(TRUE, TRUE, TRUE); + platforms[0] = platform_0 = nm_linux_platform_new(NULL, TRUE, TRUE, TRUE); platforms[1] = platform_1 = _test_netns_create_platform(); platforms[2] = platform_2 = _test_netns_create_platform(); PL = platforms[nmtst_get_rand_uint32() % 3]; @@ -3823,7 +3895,10 @@ _nmtstp_setup_tests(void) test_software_detect_add("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); test_software_detect_add("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); test_software_detect_add("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); - test_software_detect_add("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add("/link/software/detect/vlan/0", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add("/link/software/detect/vlan/1", NM_LINK_TYPE_VLAN, 1); + test_software_detect_add("/link/software/detect/vti", NM_LINK_TYPE_VTI, 0); + test_software_detect_add("/link/software/detect/vti6", NM_LINK_TYPE_VTI6, 0); test_software_detect_add("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0); test_software_detect_add("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index c18886c9..cebd44f6 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -31,7 +31,7 @@ test_init_linux_platform(void) { gs_unref_object NMPlatform *platform = NULL; - platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); } /*****************************************************************************/ @@ -42,7 +42,7 @@ test_link_get_all(void) gs_unref_object NMPlatform *platform = NULL; gs_unref_ptrarray GPtrArray *links = NULL; - platform = nm_linux_platform_new(TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); + platform = nm_linux_platform_new(NULL, TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); links = nm_platform_link_get_all(platform, TRUE); } @@ -101,456 +101,486 @@ static void test_platform_ip_address_pretty_sort_cmp(gconstpointer test_data) { static const char *const EXPECTED_BUFFER[3] = { - [0] = ("5b1aea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218074e48000000cb504e03d53e1124c5" - "0065aeb2e6fbf952902383028e3b47f2111d891d17a47631c169f11ff9119c40b468b66331bca67a" - "034f43340d02683c7545097aea4a849f060ddf57004a5be9b10123e6e4f15ecd1dff045298cfee06" - "b7f0318a03000000061db3dd7fde25654a4059d565dbc8a91e014457000000db56189572f32f4af5" - "00d785d5c1b5aad487c192f08bd7a09bdd2144439c88b02a0300000004b0595daf37deb499996bfb" - "667f072dec035d9c000000f4409bcfb3c167090e00d90a8543961b2ccd47724a3c460ba85183f4c5" - "a7afe28303000000d05ff720b16c73761a3fcb675219061ab402c7940000006a883c146972decb8b" - "00dac8f5e6d66df46ea139107754dee62c36d2fc6aae660b03000000fc1fb23d24438387def0f4c6" - "544e4b275d037146000000d349adc17647176b7c00d856e3b883efebc09dd9d61966b7ae7412041d" - "e5fe7d360300000066a3ae3939762df33a2d55060c78d551cb0310fd00000043b9aca07b6e4925dd" - "00943a272c171ed15abbbe1cd911db7b56e8f3fe6f0e9e6903000000ec2e2924348352d715cf9d41" - "1ea012e5300294b6000000c528ab20075efee38d006f8ee4ccd2f50c30706cae3fdcc2f0ee3d5e26" - "dac12ebd03000000667224dae775e5ccd141aca2ff0f57676702648100000086b62f22ca33478e1f" - "001715df7fc6a902edae579e2e10c7f7a22ba0340436242c03000000ee3fbc164632d4f28aa28c08" - "f80dd50c6702dfb400000023a28fa772a19cdf6d00c173f6078a806d329c9b008bbfc9723107f3f5" - "bcfe97e1030000007ad742d3d7320a4f880cf47f5dd0cf69cb0d840f0000007749509cb6752b2cee" - "00b7e7736a0afc9879ea40e69710fc9f6e8e99cdabf85f0c0300000008d33a2ea67776d7f88d69c8" - "c7e3b2d3c900f05400000021abb42316c533d9c90088189c471a1ff2f0ce3ff66e782110125ae2ed" - "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f6002f061d45d864d09f4ecf17625f82d" - "00c748288ae21e371051852c972ea7954079884a6c0fc09c03000000809829af4a9df58dbfef186d" - "416f3a1ef102d10f000000675203d82a3c84c4eb274ed18687780281d47a32f2235376239daeaacb" - "3cae864b0300000091921681c2162b9bfa40546cdb544e44df037c270000009a051bb2ee8192ac0c" - "fa3abc1ea0ab3e7d75a2f42b50c6a363401323780422ae3f03000000c43bd794c697895e5bfe47c6" - "f53a54e01b021d89000000d3e02d2ec587fc330003781b0f294a2b73c4421398f4de67e9cee64b38" - "ae8cb60b0300000038d856a40c67c3d4afa9c8649da90bd2ff02f2560000000bd7d5f14870c6d18d" - "6242b356955e1a13d1111b067acbce3e3bcdf382bb0ec36f0300000064a2827b7cdd38d0314c178e" - "925b568ae512c4e9000000e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" - "36674cde0300000054cfe8f42bf0e9381ba2c4396de60f032b00f34de2959871c0d4c0d4eb720c4a" - "e3c9472e5f2da5d9c5cfd9f2343b21362c19a09269121aec030000000fcc00ac2daa755e5292cd32" - "dc096cd5d802c5cf3351ee1cfcc2056cc1ff8e51bbce426cfa4b861cc78592be7b14e7ba9c15acb8" - "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa70031205000000f39b098b43cd68be6e" - "3f81268193fd637e585287dc6ca972a2cfb18b2bf6989d2d030000006ff7add5df2c93e05459507b" - "5d8c6a0f460554d2000000a8c67b2e48b47003c81785d3ffdbd9a617857ae8126b028c0e3e295354" - "bc51e540030000006c3d048a92d3adc69a84eb47622400207700416a00000087fbd7e2f7dea0077a" - "e9c0c0d9c386e9c6e6a2cbfa10ee58bdc75183607c52a52d030000004e8e8bc17c01ac63eca0c1cf" - "bb204132fb0213e4000000c2303dd1d65c7b2cffeca6d1adaccae11f8045a80f855ebf3b772eb2b1" - "bae87d60030000005d31e5b2de252167c1c91b3a36ba0c700e118477000000b913a353edc66efc06" - "8829c0e66ad0143a0554efb46b382ab0404cdf027a899f2d030000009bf5a5d06776e66a9d80ab13" - "2e1ac921eb01adbb0000002f561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" - "daae7d6303000000c0982b283aa9986700b2a2b3ed257b8b041df48f000000cac72105b327335a25" - "a364d1015ffac03089f45539e1b0178462156cd6c4e1966803000000b3121cd5ef51e696c816290d" - "baee0e77260a82e1530ff5397c9125f59577d71c4b258a005116d11354edff62ceaa458fc75a91c4" - "d03bc90503000000eb760e3f004a2efc8ffc96b89b1bc8f415034e77be46bae5a1b3cae76665a268" - "abfe8a41d149f074a378b881153ece68ade15cec7625ca4a03000000e682f80f94315c45ef817264" - "c89a736ed51dd637b077ddad3108be69f9b97d05c917ad6b10e693bb6e26f2ba90c8e909e85e20e5" - "2af145480300000004265f6c72923e22594f3f79e208ed2e2e020771db46a54cadb245eafde6b025" - "67f814de39dd8f88152a58454d9ca9d20f45dfa700154d12020000009edfa7a74c1c83c18e47935e" - "8354846e3403386a000000d94064f6b021281e230094ae20ac26c7d41fd050bf8d85055bcfe3756c" - "98c39e7c02000000efc57ff447036b9551adcb22fd50793f79103c7d0000006e759d0c90bc512e13" - "00cef5e4a27985bd8d1e69c83dc21056b973972c6855676c02000000017c9148da5892bb4951c3a7" - "ed55689d3305ce7d3fd48469845f0c233dbdd2a90035df1f1782dee88487fd0db5971b46b7a350f9" - "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c01a56dfdcfc1155f236c8b9c79a620" - "00660bbf024b03ff0a8e27c405e6424457393c6f74993ade02000000e62112898dab2dade2ab2fc9" - "c56a7c86be0296228ec3f2f439d949b22b9c161c00b745cebdd06352cb2c354434819f4b248eb2b8" - "6297dfa702000000fd0d53bb6215de4bb6f6f3d031a790287e06e9c18bb836c0a25ea71f5daaed4d" - "00eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a46e91b91502000000be5b534e0a6527f67485ab35" - "aca0c7ee4102338500000063e66e3a23d6732578acd14320aefd4503189f7630248e501c9052c22b" - "e3ff1a5f02000000b4425486c619147eb0216050ed7afd741000e83600000011f9c797c0c0ec468e" - "9de5a9caf493472201e48d163106cc397446a33fa349e1cc02000000b879a45176740744fcb6a035" - "339d504c9719d80d000000df765b4d9a130257dc5ff7f03a9518862bc9a89192c1c8be55281a59d1" - "bcd7be0702000000e45aaf61814f703b40125e6baf4648cbaa1f7b86000000dafe7d6ec4ac1ea051" - "010911915ddb05f2a84e27c18a06e2c9cb29efdfb56e03e0010000002f70249eefc67bce716c856e" - "3973dc42a1033be9000000efb1f14d985d5bbe6c00085f3d6176f78a19bb8df1804c122fce5078c1" - "57d6249b010000007dc7f17f666969e45c3baf7a119a65ee0b01fa9e000000f3de6dc8dfcf2a3ad3" - "00cc0fa3b314f695bd82e9ea8891ed0a3d1b91ca4f1b134801000000449a774929e86716ec852d59" - "f3d17232ed026ad600000068843a9aef34983882004f24a17dba1ee7e143fd52599364e13468f80f" - "fc1519de010000002545666937c22a3b6e9686dcc405cbee5000c2520000001f7a0165fe20744edb" - "00a04f146e4c699341b95f41d9c1e67743efb54e54270e46010000006a894e387625da376feecb80" - "ac245409c003cc2700000067179bff0644399ae70064ed0432d599eaa660ac824b7fae389861419c" - "9f3c2c8801000000f51f44e644d7cf1d06b2b115d882549e62002fba5b1cdec48d10bbb13b8313d8" - "002a24d34fc812bd2f8a59d96d064126666befbb81ae55f0010000000aa20624fbab244735d67c61" - "283031667b0274a103e0b1b153222aa590a2312e00f1a35900459582f4ef43c780908872746e39ef" - "536c75bb01000000720da9e07ac998b5690807d52617369ee1004ca500000081af5fd7ceacdca10f" - "00d7b351a36b178aabc78a4a0d80684ee5dbf45bc7a4c65601000000cd625009a40aeb62a42b6a62" - "548e3c38b9002002000000fbfaf1809becd2506300a6da29b2e94d3ab51fe0e9af98b180a36035fb" - "f05d7308010000009d82c856ba942455050f63f8282f34644402acf5000000a54b7892f487afa98c" - "0021c19c69d9942f460bcea75481f25e307d0de959747cf201000000ab2dadc5a39411fd4ff1116d" - "478987316a0e3fc2000000cfc6ebe434a7ae8ff040483e310819e3b10db116431ec6f7691539ce41" - "d514573f01000000f6932f6932d1d5f5d0ce2cf6bf7a70ba5100a1620000001b11d9172cf84a0347" - "8b82cdd8883b0f3fd6ed84d6c959e553b887edcdf90e54b501000000a779f37c30d2c5053c40ecae" - "210aeb0934012a247000b96d06992b6a58acd3995b9663d2df48f333ef467092818aa77d6732b678" - "cf844ef501000000cd743f59bd14c89b5cfd5ce6e82e785415032b7000000043e0f79ab6902dde53" - "36b3ec7127e19f254ac9588319558041fc62ed564153e174010000004d89c0bb5408c1b7d17fb084" - "d9e1825fa602e1af0000004b7f9e85ff73e050a2cd89fd276e08cb887464b9344ec3127c750fabdd" - "9985d62701000000e491cbbbf9443fd6a77eb3c5bf64b671d6068dbf0000008306c83bc026977911" - "4bdade862c224f6f36506ebd455e679cef369bb8fc2b445701000000496ad01bf007eacb0a28aec8" - "68282510b61e91ea6480e356def85b75827b26e8a0bef8675b29a197b7b3cceaf5f1bb12c535256a" - "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e1700b60000006dae02dfa0c26e7c3a" - "00603bd35e7fa0f02f2f3313d8469d09a92409c0f257b044000000006a4c619f9037d7a754655354" - "c47cf0f5510167700000001bef820fe02931f2d30075049150b8d10ab700cc3a7cf51be0403b654b" - "10613fc90000000016a31dc2e46a234558817151b38fc9c909038d71000000d761fdf274fc5dca8c" - "00bd1871ae17bb4515856092b4d9e89b676761b2eecc89f600000000d635edea8ffe423d01883918" - "039249f39800b37e00000053b2a16e643722d9b700c0d8a41fb7c8307f06b4b29088f20d9ac676d5" - "4d4647f5000000000f88e3759a08e7a56663861eea1bf42ccd0572f200000057ca82ac5180101be4" - "005cef468ea086ea9aaafdc388811ec787bc45db50da49bf00000000d94beb259f9f0251becc9879" - "07879cca681ec7bb000000df248b49953d136cac00054b019402a4c2167721673f2b02b3256ead1f" - "02e9b69000000000eacce745ea213cb1a84035b632ef3be6071fafa202187470e9da55709427c226" - "0024d9a086ed27184b443181a5edc511c1507a142fea9bc10000000062fb81e733cff620ca7feefe" - "1933631e8e03f6d90000002f6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" - "cdb3455c00000000c66af76e80f062ea1a7e0b7be218d06753001b04000000bb9f2b8a1a8982c42f" - "53700a3437c5156e072b2f2fb337c9cfe07c34ddb83579b80000000072437f9b6245de39ec9e71ee" - "4b951507be002b340000000f895d5f24037d233302ad3b82d639272e4a46eadfbd2146bf8cfdb205" - "ebfdcec30000000067a982be8a934f852cc3d4d82bc0ec7303129f8f00000087965a316af2abb982" - "b001ec16901f55f960c55c22f32099a8020bea2a25a5927300000000c4458d70911714f1819aa46f" - "be143934c900ae6dec0fb124f264af67eed7c9a8c38b6b8ee2614344bea73223e59bf0193432e9fa" - "b4d54acb00000000a417f3da01d99dae5f190096cc582cabd51fd15a0000003edc5aa115165eb914" - "d8fbe9a4fdb3d117d76b0de5416f95e7bb75d72f4cc43c5100000000c2aac1d67a909b297c703915" - "312e9c3c5a03c40b20ea99d5ab90135fa636af4464d210a256be75e0509c4477d19ac64b2e69220d" - "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ec17fb112087b97cfcebbaeb0c565359" - "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9b2cd3dbd00000000e958e48d2ab8b0313e7f8933" - "e315130fa9034c8288f83f6e70b1646d8026e9f1704f1b16286ba2dabc7ef0820c91ed33ef60a8b5" - "70ccc567df7a49b8a4c73cf5ffa4ffc8a4bab14874afdf54e60fe816a9fe07ca0675e09818e9bbec" - "0018c59068baf76ab08940f6fc3bbdc7f6090f7512ea3b9503000000fb95e8332fdfff658483a2d0" - "39a7bf148e01481ea9fec460e89f7abdb682380a00eae374835b4a49a2b980b6aba92da6409969aa" - "fd338f35030000006e8cc34573654ea6624f138ef9531cd9360002e4a9fe989477a363d55ad47b8a" - "11090df8da40d88d40a6d75bc404156225b7eedeb95c593103000000dbe9962069e66142e2275334" - "4fda8a3e0b001cf7a9fedd68269b53eccb44a831714acfb58c54dda9ac3bb1b1d43e6505621b9a7f" - "1e0f515603000000f57609453df7803357ae79989870ccec3d000ad9a9fee016663fe6ee0228c1da" - "5f5b481b9f05a16768cb3bc873b04d937a6ed8f7d7ac5f9903000000822a272bec4501a1e27acfee" - "7a8588ffd5016caea9fee59560fad65d67c624f285d7174177a47579dda0b6ead1e1b34901eaedd5" - "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a011480a9fec42cac4ef3ad378ffec7" - "085a62475588456e4ead7cbda620a3abae816e345d68265d020000009b7a559be3acf4fc36fa6b51" - "3cf09e8b99009462a9fe10acfce165e332a623840004e5bab49185ad9b7d0070a36dd51323b2c542" - "dedea2030200000002a1f8e6f5657f3f9e3eb807cbad76451002edb8a9fe628a70456d79f25d5895" - "0057fa60d9279fb2b8fcbac6abea74f7a6df7979b3980deb020000006c1de913df1424ce3ee1d76f" - "c1ea76e98c00fc78a9feb53e27c21963f5b4cb2454830c68e44ea74b4f2b83f9b3bee14d861a4c9e" - "bc74179402000000438a72e12ae0436a2495a609675344f7e200a5eba9fec85f0a1742f70abe95c5" - "0345132a61eda239d9d083c3bf085387046ef8a3b0916e5d020000004a503a712350acbd48411f0d" - "c15d2f0f4903d345a9fe06954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" - "9a6ce5d902000000a6a5ee19d6f63fe9cbdd01f7246f13b2050524a2a9fe5ef7a029c896b4132bd8" - "95072cfeffe9d6812231bb02f922259b173c333c1dce2f83010000003a3efc240b9977e166bee737" - "fe73670c4301644ca9fe59b4cd20eb7dd3d38785008ffad45e0dfe491d1ba96742c7b5e02b227122" - "a9a89f8701000000fcdf6d9be94030b34774d1d7dddedd989901f627a9fe965a87041331b2834bcf" - "00b4e3ce848518c4e3f6cbf25e5e1b990fc46767e36f90d401000000fd41fe47684b370b6ec6584d" - "64496089570368eaa9feae91c819bb068196d59900de3246e43f5e7945aaf95e2ffa3a11b9ef1b21" - "74e7860401000000cd7db68b9ae586dacdb4070c50320427c4033d03a9fef22c636360d696be085a" - "007c499dd538d34574c038404923e75d0e09e2fcaefd545b010000007ced4f8b362956cd46646a0e" - "222160e5f700bb29a9feed37a2123c5b6a813387e99bb834a19da86c64fefab2548759d313a5b92d" - "c896c9a7010000000a5f6abd850b06e3d9662795ce2cc1cee01702aba9feaaa218dc091e9aa1477f" - "6fdc9830d7fbc95829a8838314dff34d24c332219a1b163a000000000e2f4f911a0dd8c052ed6b13" - "e2815a1a37002bdda9fef1018b587eed72bb58f000201f17bd99fcf72909ac9e7a55299e9bb4fd53" - "7666c05300000000ffa8e89871fb9510b900b2061d0c334b81022dd1a9fe4b0f9a60e0e289f08db3" - "00bafc4e095a3230fde69eec3af2e6d0bd68ab722cb749e2000000000eb4f73e75039fcf251b32fc" - "79685b05dd02aa9ba9fed2e40edb4d758fb554158ae5c7c00d58fbcc58fc4c2fd0d44ff1e51c3515" - "40b26f6600000000badfad0fe8fa8f3c1aad2a82530b7447d902f401a9fe2f4c329f997184c9d257" - "8e4cf9c48147507e1cd59ea1ae6da48b1eba6d16672d2fa500000000e276c5661a64192db44ce7af" - "5eb888e9eb03bb04a9fe943b101e1f553215abf8fbdf17c3641e447514ca565fb9b68c08a5e4351e" - "a2f5680800000000faa100fdfdd68d34be184524a6bdc8789c035178a9fe5bcc8da98489c55b8c12" - "87e6f7bb020ffdb0e612098610e52bb2a16a40089f3c39f200000000de745cb25851429b3bbfb501" - "68dfd04edf033542a9fe5f574c5cf8107ba282f4f983821918f93e742d08f0550b55726f2292362e"), - [1] = ("54270e46020000006a894e387625da376feecb80ac245409c058cc271d9c2f67179bff0644399ae7" - "9c64ed0432d599eaa660ac824b7fae389861419c7a899f2d010000009bf5a5d06776e66a9d80ab13" - "2e1ac921eb04adbb229df32e561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" - "c4e1966800000000b3121cd5ef51e696c816290dbaee0e77264c82e1530ff5397c9125f59577d71c" - "4b258a005116d11354edff62ceaa458fc75a91c425a5927300000000c4458d70911714f1819aa46f" - "be143934c915ae6dec0fb124f264af67eed7c9a8c38b6b8ee2614344bea73223e59bf0193432e9fa" - "4cc43c5103000000c2aac1d67a909b297c703915312e9c3c5a64c40b20ea99d5ab90135fa636af44" - "64d210a256be75e0509c4477d19ac64b2e69220d12ea3b9501000000fb95e8332fdfff658483a2d0" - "39a7bf148e4c481e0bccc460e89f7abdb682380a62eae374835b4a49a2b980b6aba92da6409969aa" - "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ec5ffb112087b97cfcebbaeb0c565359" - "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9bb0ec36f0000000064a2827b7cdd38d0314c178e" - "925b568ae566c4e9fefb24e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" - "02e9b69000000000eacce745ea213cb1a84035b632ef3be60755afa2fed87470e9da55709427c226" - "d324d9a086ed27184b443181a5edc511c1507a142fea9bc10300000062fb81e733cff620ca7feefe" - "1933631e8e18f6d9fed62d2c6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" - "9985d62700000000e491cbbbf9443fd6a77eb3c5bf64b671d6098dbffeff9b8306c83bc026977911" - "4bdade862c224f6f36506ebd455e679cef369bb8d514573f03000000f6932f6932d1d5f5d0ce2cf6" - "bf7a70ba5111a162fe92ec1b11d9172cf84a03478b82cdd8883b0f3fd6ed84d6c959e553b887edcd" - "6297dfa700000000fd0d53bb6215de4bb6f6f3d031a790287e7be9c1feb836c0a25ea71f5daaed4d" - "99eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a41e0f515601000000f57609453df7803357ae7998" - "9870ccec3d4f0ad9000000000000000000000000000000019f05a16768cb3bc873b04d937a6ed8f7" - "ae8cb60b0300000038d856a40c67c3d4afa9c8649da90bd2ff4cf256000000000000000000000000" - "00000001955e1a13d1111b067acbce3e3bcdf38200154d12010000009edfa7a74c1c83c18e47935e" - "8354846e346e386a00000000000000000000000000000001ac26c7d41fd050bf8d85055bcfe3756c" - "a2f56808092069affaa100fdfdd68d34be184524a6bdc8789c575178000000000000000000000000" - "00000000020ffdb0e612098610e52bb2a16a40086f0e9e6903000000ec2e2924348352d715cf9d41" - "1ea012e5305a94b600000000000000000000000000000000ccd2f50c30706cae3fdcc2f0ee3d5e26" - "81ae55f0030000000aa20624fbab244735d67c61283031667b2274a1000000000000000000000000" - "0000000000459582f4ef43c780908872746e39efaefd545b020000007ced4f8b362956cd46646a0e" - "222160e5f749bb2900000000000000000000000000000000a19da86c64fefab2548759d313a5b92d" - "f05d7308020000009d82c856ba942455050f63f8282f34644466acf5000000000000000000000000" - "0000000069d9942f460bcea75481f25e307d0de96e91b91501000000be5b534e0a6527f67485ab35" - "aca0c7ee4167338500000000000000000000000000000000aefd4503189f7630248e501c9052c22b" - "5d68265d010000009b7a559be3acf4fc36fa6b513cf09e8b99729462000000000000000000000000" - "00000000b49185ad9b7d0070a36dd51323b2c542e5fe7d360100000066a3ae3939762df33a2d5506" - "0c78d551cb7410fd000000000000000000000000000000002c171ed15abbbe1cd911db7b56e8f3fe" - "9a6ce5d900000000a6a5ee19d6f63fe9cbdd01f7246f13b2055624a2000000000000000000000000" - "00000000ffe9d6812231bb02f922259b173c333cbae87d60000000005d31e5b2de252167c1c91b3a" - "36ba0c700e538477000000000000000000000000000000006ad0143a0554efb46b382ab0404cdf02" - "7c52a52d030000004e8e8bc17c01ac63eca0c1cfbb204132fb0813e4000000000000000000000000" - "00000000accae11f8045a80f855ebf3b772eb2b1d03bc90503000000eb760e3f004a2efc8ffc96b8" - "9b1bc8f415174e7700000000000000000000000000000000d149f074a378b881153ece68ade15cec" - "7666c05303000000ffa8e89871fb9510b900b2061d0c334b816a2dd1000000000000000000000000" - "00000000095a3230fde69eec3af2e6d0bd68ab7210613fc90200000016a31dc2e46a234558817151" - "b38fc9c9093c8d7100000000000000000000000000000000ae17bb4515856092b4d9e89b676761b2" - "57d6249b020000007dc7f17f666969e45c3baf7a119a65ee0b08fa9e000000000000000000000000" - "00000000b314f695bd82e9ea8891ed0a3d1b91cab56e03e0010000002f70249eefc67bce716c856e" - "3973dc42a1003be9000000000000000000000000000000006176f78a19bb8df1804c122fce5078c1" - "eecc89f601000000d635edea8ffe423d01883918039249f3984ab37e000000000000000000000000" - "000000001fb7c8307f06b4b29088f20d9ac676d5f90e54b501000000a779f37c30d2c5053c40ecae" - "210aeb0934392a2400000000000000000000000000000000df48f333ef467092818aa77d6732b678" - "bcd7be0700000000e45aaf61814f703b40125e6baf4648cbaa557b86000000000000000000000000" - "000000005ddb05f2a84e27c18a06e2c9cb29efdf50da49bf00000000d94beb259f9f0251becc9879" - "07879cca6857c7bb000000000000000000000000000000009402a4c2167721673f2b02b3256ead1f" - "a349e1cc00000000b879a45176740744fcb6a035339d504c972bd80d000000000000000000000000" - "000000009518862bc9a89192c1c8be55281a59d1ebfdcec30000000067a982be8a934f852cc3d4d8" - "2bc0ec7303579f8f00000000000000000000000000000000901f55f960c55c22f32099a8020bea2a" - "5b1aea3401000000c7c3523f76cf1ce34ca17a9a32f3f0f2187c4e48000000000000000000000000" - "00000002e6fbf952902383028e3b47f2111d891d536c75bb01000000720da9e07ac998b5690807d5" - "2617369ee16d4ca500000000000000000000ffff47d7b351a36b178aabc78a4a0d80684ee5dbf45b" - "17a4763102000000f9119c40b468b66331bca67a034f43340d2c683c00000000000000000000ffff" - "b24a5be9b10123e6e4f15ecd1dff045298cfee069c88b02a0300000004b0595daf37deb499996bfb" - "667f072dec755d9cdc8a11f4409bcfb3c167090e99d90a8543961b2ccd47724a3c460ba85183f4c5" - "a7afe28302000000d05ff720b16c73761a3fcb675219061ab466c79489b2cc6a883c146972decb8b" - "5adac8f5e6d66df46ea139107754dee62c36d2fcc7a4c65601000000cd625009a40aeb62a42b6a62" - "548e3c38b96620022753c5fbfaf1809becd2506315a6da29b2e94d3ab51fe0e9af98b180a36035fb" - "e36f90d401000000fd41fe47684b370b6ec6584d64496089574568ead4d1ae91c819bb068196d599" - "efde3246e43f5e7945aaf95e2ffa3a11b9ef1b21cdb3455c00000000c66af76e80f062ea1a7e0b7b" - "e218d067532d1b0487b8c3b99f2b8a1a8982c42f53700a3437c5156e072b2f2fb337c9cfe07c34dd" - "c896c9a7000000000a5f6abd850b06e3d9662795ce2cc1cee03202aba042aaa218dc091e9aa1477f" - "6fdc9830d7fbc95829a8838314dff34d24c332214d4647f5000000000f88e3759a08e7a56663861e" - "ea1bf42ccd1172f2ad063857ca82ac5180101be4f85cef468ea086ea9aaafdc388811ec787bc45db" - "7625ca4a00000000e682f80f94315c45ef817264c89a736ed580d637b077ddad3108be69f9b97d05" - "c917ad6b10e693bb6e26f2ba90c8e909e85e20e5b0916e5d030000004a503a712350acbd48411f0d" - "c15d2f0f4952d345599706954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" - "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa700b120523bd98f29b098b43cd68be6e" - "3f81268193fd637e585287dc6ca972a2cfb18b2b3cae864b0200000091921681c2162b9bfa40546c" - "db544e44df587c2790d3119a051bb2ee8192ac0cfa3abc1ea0ab3e7d75a2f42b50c6a36340132378" + [0] = ("8d1e69c83dc21056b973972c17a47631c169f11ff9119c40b407b6630000007a034f43340d01683c" + "0045097aea4a849f060ddf57b24a5be9b10123e6e4f15ecd9c88b02a06d0dc5504b0595daf37deb4" + "99996bfb667f072dec025d9cdc8a11f4409bcfb3c167090e00d90a8543961b2ccd47724a3c460ba8" + "5183f4c5daae7d63ecc8fb1103000000fcebbaeb0c56535923f14874042a8aff1d018e5e000000cd" + "36bbe3c9bb0ec36f00e007bb64a2827b7cdd38d0314c178e925b568ae56bc4e92931f2d303000000" + "50b8d10ab700cc3a7cf51be0403b654ba2026808092069affaa100fdfdd68d3400184524a6bdc878" + "9cf851782d895bcc8da98489c55b8c1230d2c50503000000210aeb0934cb2a247000b96d06992b6a" + "5803d399000000d2df48f333ef467092008aa77d6732b678cf844ef5a943825fcd743f59bd14c89b" + "df6f628a03000000f25d5895fb57fa60d9279fb2b8fcbac6ab0274f70000007bf6989d2d6a909e98" + "00f7add5df2c93e05459507b5d8c6a0f466554d2ae4d52a89427c2260300000086ed27184b443181" + "a5edc511c1507a141e03515600000033f57609453df7803300ae79989870ccec3def0ad92749e016" + "663fe6ee0228c1da5f5b481b0300000068cb3bc873b04d937a6ed8f7bc51e5406603d0980000008b" + "92d3adc69a84eb47002400207799416af1f0a086fbd7e2f7dea0077ae9c0c0d9f264af6703000000" + "c38b6b8ee2614344bea73223e59bf0193402e9fa0000002d8ec7e4b89bf5a5d00076e66a9d80ab13" + "2e1ac921eb76adbb229df32e561fa80aabf85f0c0300000008d33a2ea67776d7f88d69c8c7e3b2d3" + "c902f05400000020abb42316c533d9c90088189c471a1ff2f0ce3ff66e782110125ae2ed74993ade" + "507e308d030000008dab2dade2ab2fc9c56a7c86be5f96228e02f2f4000000b32b9c161c36b745ce" + "00d06352cb2c354434819f4b248eb2b8e3ff1a5ffc386da337c27c15030000007e5c53e755c90fa0" + "9e9653ddcb1b14d2750d8a130000001734b49e955cbcf46d006a1818053da43ec5085d1df74d1e28" + "7271092897e26251de485b1303000000957c22721583c453d15ade4386ffd00b3600858900000013" + "f09e601d88d4cb0c004d15c69e89f94ef7b30486591030639eb0e99f7f53702f3c84c4eb03000000" + "87780281d47a32f2235376239daeaacb3c02864b000000ae91921681c2162b9bfa40546cdb544e44" + "df2d7c2790d3119a051bb2ee8192ac0cfa3abc1e0300000075a2f42b50c6a36340132378b95c5931" + "3b03ba640000002069e66142e22753344fda8a3e0b841cf76391dd68269b53eccb44a831714acfb5" + "c442139803000000cee64b38b56e03e0f121014a2f70249eef027bce0000006f3973dc42a1003be9" + "4f89d8eeb1f14d985d5bbe6c10085f3d6176f78a19bb8df1449a774903000000ec852d59f3d17232" + "edd86ad6c3103a6884029aef00000082594f24a17dba1ee7e143fd52599364e13468f80fd514573f" + "b572671cf6932f6909f4ecf103000000a1c748288ae21e371051852c972ea7954012884a00000045" + "fd13a6826a4c619f9037d7a754655354c47cf0f551e96770a754ac19ef820fe0eafb1ac403000000" + "3aa9986700b2a2b3ed257b8b0489f48f0500c8cac72105b327335a25a364d1015ffac03089f45539" + "e1b0178462156cd6b83579b8da27345a4d9ca9d20300000074e786047d8683facd7db68b9ae586da" + "cd03070c00000027c4dd3d031e33f22c636360d696be085aad7c499dd538d34574c038404923e75d" + "36506ebd03000000ef369bb8ebfdcec3f8c8fa6867a982be8a054f85000000d82bc0ec7303f99f8f" + "e8d07c84965a316af2abb982b001ec16901f55f960c55c22c896c9a7030000000a5f6abd850b06e3" + "d9662795ce2cc1cee00002ab000000a318dc091e9aa1477f6fdc9830d7fbc95829a8838314dff34d" + "24c332219a1b163a8483a2d0030000008ed3481e0bccc460e89f7abdb682380a6202e3740000004b" + "a2b980b6aba92da6409969aabae87d60e00473755d31e5b2de252167c1c91b3a891715df03000000" + "edae579e2e10c7f7a22ba0340436242cbe11248c000000174632d4f28aa28c08f80dd50c6712dfb4" + "d184e820a28fa772a19cdf6dd1c173f6bc7ef08203000000ef60a8b540b26f66761d1f13badfad0f" + "e8038f3c1aad2a82530b7447d9c2f401012f2f4c329f997184c9d2578e4cf9c48147507e1cd59ea1" + "6e8e99cd03000000644f0e8ab3121cd5ef51e696c816290dba010e77000000e1530ff5397c9125f5" + "9577d71c4b258a005116d11354edff62ceaa458fc75a91c45cfd5ce603000000152f2b70eaef7443" + "e0f79ab6902dde53361dec71000000254ac9588319558041fc62ed564153e17478f8c3344d89c0bb" + "5408c1b7d17fb084b16c7376030000005219061ab4c5c79489b2cc6a883c1469721dcb8b5adac8f5" + "e6d66df46ea139107754dee62c36d2fc70ccc567df7a49b8a4c73cf5ffa4ffc8acdca10f03000000" + "a36b178aabc78a4a0d80684ee5dbf45bba0210fb9733cc24904f288262e6ea77a22fa5f863eaeefa" + "701d120523bd98f29b098b43cd68be6e37686b5e030000006215de4bb6f6f3d031a790287e45e9c1" + "8b0236c0a25ea71f5daaed4d99eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a4f05d7308b67f91bf" + "0408423e03000000886dc91e2e5b0f0b65843fc961f7ad18010a3c67d9714f19f1e41c073164d93b" + "1171719c7f81773302d007c983566139c695e0f4b661ee6b3cf09e8b02000000e79c10acfce165e3" + "32a62384ec04e5bab40285ad00000071a36dd51323b2c54200154d12f86c260a9edfa7a74c1c83c1" + "8e47935e8354846e27c219630200000054830c68e44ea74b4f2b83f9b3bee14d86034c9e000000f6" + "abba4a32d635edea00fe423d01883918039249f398f9b37ea0914651b2a16e642c19a09202000000" + "92defa453a3efc240b9977e166bee737fe10670c0000004c323b59b4cd20eb7d00d38785c88ffad4" + "5e0dfe491d1ba96742c7b5e02b227122fcd32a7f0200000023a5223a2fb2c0764e08db62a3db07d0" + "900260b922a7b4a1565e63d3b610c9df00e32703b0ed3a7d0f8b13cd736aaa72021a381fb50e2c42" + "54270e46020000006a894e387625da376feecb80ac245409c005cc271d9c2f67179bff0644399ae7" + "0064ed0432d599eaa660ac824b7fae389861419c50da49bf8c3b371502000000710c030690f5f18e" + "a125dbf7d7e93bd65c01a56dfdcfc1155f236c8b9c79a62000660bbf024b03ff0a8e27c405e64244" + "57393c6fd7ac5f99544e4b2702000000a7f810d249adc17647176b7c07d856e3b806efebc09dd9d6" + "1966b7ae7412041d00fe7d361f2d5dfd66a3ae3939762df33a2d55060c78d551fcb6a03502000000" + "9726d80d9c2d89df765b4d9a130257dc5f19f03a0000002bc9a89192c1c8be55281a59d1fd338f35" + "7e75f8ce6e8cc34573654ea6624f138e8c45eb5002000000562dcd24a27c8212127da516b1091d1d" + "4f0008170000000d32d823b0617718eb0f3195e2fe917423d314ae73572ff808b373f5b193d661ed" + "e45aaf610200000040125e6baf4648cbaaa37b861e6d46dafe1f6ec400000053010911915ddb05f2" + "a84e27c18a06e2c9cb29efdf672d2fa57fc85ebbe276c566804c122f0100000059747cf23a1349c8" + "ab2dadc5a39411fd4f03116d000000316a553fc28cff0bcd00ebe434a7ae8ff040483e310819e3b1" + "0db116431ec6f76949ba9be3010000000c67c3d4afa9c8649da90bd2fff2f2568101870b0000004b" + "70c6d18d6242b356005e1a13d1111b067acbce3e3bcdf3824f1b134847ff26ba32d1d5f501000000" + "bf7a70ba5193a162bc92ec1b11d9172cf8020347000000d8883b0f3fd6ed84d60059e553b887edcd" + "61c2f5d2f381f843b809d259e499db7d2b092583010000009f9f0251becc987907879cca68fec7bb" + "bb008edf000000973d136caca5054b010002a4c2167721673f2b02b3256ead1f2fea9bc12f0cfca1" + "62fb81e701000000ca7feefe1933631e8e69f6d9d6962d2c6e0304f50000009e47150b9b14010469" + "003acb72bb89182f931121966e91b9153b36bc60be5b534e1dff04520100000036674cdefb57b9ae" + "54cfe8f42bf0e9381b00c4396de60f032bc7f34de295987100d4c0d4eb720c4ae3c9472e5f2da5d9" + "c5cfd9f2343b21363f81268101000000585287dc6ca972a2cfb18b2b2cb749e2e002544d0eb4f73e" + "75039fcf251b32fc00685b05ddd3aa9ba511d2e40edb4d758fb554158ae5c7c0fde69eec01000000" + "bd68ab722af14548b29572e504265f6c72003e2200000079e208ed2e2ebb07710046a54cadb245ea" + "fde6b02567f814de39dd8f88152a5845a4bab14801000000e6aae816430607ca0675e09818e9bbec" + "5900c5900000006ab08940f6fc3bbdc700090f756aae660b3b02239efc1fb23d24438387def0f4c6" + "cbb110fd01000000b9aca07b6e4925dd27943a272c171ed15a02be1c0000007b56e8f3fededea203" + "00a8042602a1f8e6f5657f3f9e3eb807cbad76451055edb81539ce410100000018238487a417f3da" + "01d99dae5f190096cc0e2cab0000005b2363d13edc5aa115165eb914d8fbe9a4fdb3d117d76b0de5" + "416f95e7bb75d72fc8f1853b010000000e2b00b667b7b16dae02dfa0c26e7c3add003bd3000000f1" + "2f2f3313d8469d09a92409c0b7f0318a575a4f8e061db3dd7fde25654a4059d5d8a4c5cf01000000" + "fcc2056cc1ff8e51bbce426cfa4b861cc70192be7b14e7ba9c15acb881ae55f0f512dc1c0aa20624" + "fbab244735d67c61283031667b2d74a103e0b1b10100000090a2312e17f1a35900459582f4ef43c7" + "80038872000000efa9a89f87189b1d0afcdf6d9be94030b34774d1d7dddedd9899f0f627be16965a" + "8704133101000000d9b4e3ce848518c4e3f6cbf25e5e1b990f026767000000bba23eb66e720da9e0" + "7ac998b5690807d52617369ee1af4ca5a6a95581af5fd7ce732d803e010000001a0dd8c052ed6b13" + "e2815a1a37a52bddd106f101000000ed72bb58f0e9201f17bd99fcf72909ac9e7a55299e9bb4fd53" + "bc7417940fcffe3fb60291ea01000000def85b75827b26e8a0bef8675b29a197b71ecceaf5f1bb12" + "c535256ab0916e5d58099ffc4a503a712350acbd48411f0dc15d2f0f49dad34565dbc8a900000000" + "b550c5db56189572f32f4af595d785d5c117aad4000000f08bd7a09bdd214443008cd9bf66ec305a" + "225a0c71b2ce78bb16104c8eaf18c56587e6f7bb00000000e612098610e52bb2a16a4008aefd545b" + "7a019db50000008b362956cd46646a0e002160e5f769bb295766ed37a2123c5b6a813387e99bb834" + "b7a350f900000000fa7db4532545666937c22a3b6e9686dcc403cbee000000529ed8901d7a0165fe" + "00744edb6ba04f146e4c699341b95f41d9c1e67743efb54e4fc812bd000000006d064126666befbb" + "98c39e7cc282208fef007ff40000009751adcb22fd50793f007a3c7dadd1c86e759d0c90bc512e13" + "7dcef5e4a27985bd348352d7000000001ea012e5307294b6e346dac428ab20075e05e38d000000e6" + "ccd2f50c30706cae00dcc2f0ee3d5e2612ea3b95e1d2a5d0fb95e8332fdfff650a6527f600000000" + "aca0c7ee4197338581cafd63e66e3a23d61e257800000020aefd4503189f7630008e501c9052c22b" + "9f3c39f24b0572b1de745cb25851429bf32099a8000000004d4647f53b1921af0f88e3759a08e7a5" + "661f861eea1bf42ccd3c72f2ad0638570082ac5180101be4f85cef468ea086ea9aaafdc388811ec7" + "3bbfb50100000000df6b3542f4bb5f574c5cf8107ba282f4f9038219000000772d08f0550b55726f" + "2292362e5d68265d9f98c82d9b7a559be3acf4fc36fa6b513722d9b7000000001fb7c8307f06b4b2" + "9088f20d9ac676d55b00ea34000000fec7c3523f76cf1ce34ca17a9a32f3f0f218424e48836dd1cb" + "504e03d53e1124c5d9e1825f00000000284a024b7f9e85ff73e050a2cd89fd276e00cb8800000037" + "4ec3127c750fabdd69121aec129cdc690fcc00ac2daa755e5292cd32dc096cd5438a72e100000000" + "2495a609675344f7e2e3a5ebaec3c85f0a1242f7000000c70345132a61eda239d9d083c3bf085387" + "046ef8a36f0e9e6982d15956ec2e2924ae6da48b00000000bcfe97e1761e12457ad742d3d7320a4f" + "8800f47f5dd0cf69cb22840f09b3fe7749509cb6752b2cee30b7e7736a0afc9879ea40e69710fc9f" + "57d6249b000000007dc7f17f666969e45c3baf7a119a65ee0b1ffa9e000000f2de6dc8dfcf2a3ad3" + "bbcc0fa3b314f695bd82e9ea8891ed0a3d1b91caae8cb60bab90135f0000000064d210a256be75e0" + "509c4477d19ac64b2e03220d6c0fc09c25d6534c809829af4a9df58dbfef186d416f3a1ef170d10f" + "2c932e655203d82a87bb24e500000000e9cf9f6df9615189f78ee815b2781ea55c1755876b6a3f13" + "922b6cb8360feaac1d5c302df59dd32a677e5a3af4fe297f608df061d45d864db442548600000000" + "b0216050ed7afd741024e8365ea1aa11f90397c0c0ec468e9de5a9caf493472201e48d163106cc39" + "7446a33fdc335c8b152c507a0a3c8e7cc67b2e48b47003c81785d3ffdbd9a617857ae8126b028c0e" + "3e0f5354a9feb690c628d048eacce74500213cb1a84035b632ef3be6070dafa202187470e9da5570" + "40e55b8b03000000c0cfb2b4386bec092fa5757ecde9348bda012ebda9fea6aa667224dae775e5cc" + "0041aca2ff0f576767d3648102b61886b62f22ca33478e1ff9531cd903000000d241989477a363d5" + "5ad47b8a11090df8da00d88da9fed75bc404156225b7eedefc2b44574b15e2ae496ad01bf007eacb" + "0a28aec8682825108c54dda903000000d43e6505621b9a7f0422ae3fc8979ee0c400d794a9fe895e" + "5bfe47c6f53a54e01b0c1d89414d94d0e02d2ec587fc330003781b0f294a2b7387bc45db03000000" + "36bd39a44e8e8bc17c01ac63eca0c1cfbb004132a9fe13e4862573c2303dd1d65c7b2cffeca6d1ad" + "accae11f8045a80f855ebf3b772eb2b1182c028703000000ec4501a1e27acfee7a8588ffd5a06cae" + "4201e595a9fed65d67c624f285d7174177a47579dda0b6ead1e1b34901eaedd5bcd7be07d78e6222" + "d611d7b103000000f9f23b5f1570a4648a0ff80dd9a37a82e10120aaa9fe258532449deb7afb217d" + "58c0bb20de6f36d664873c5be82c5361358730bcde43782d87b8c3b9020000008982c42f53700a34" + "37c5156e072b2f2fb300c9cfa9fe34ddb3980deb14ab7b5a001de913df1424ce3ee1d76fc1ea76e9" + "8c9dfc78997ab53ec386e9c60200000010ee58bdc75183609985d627b6a4b1cbe402cbbba9fe3fd6" + "a77eb3c5bf64b67100f18dbf463f9b8306c83bc0269779114bdade862c224f6fdd65aeb202000000" + "902383028e3b47f2111d891d9f3c2c88cd007619a9fe44e644d7cf1d06b2b115d882549e62c12fba" + "5b1cdec48d10bbb13b8313d8cd2a24d3be46bae5020000006665a268abfe8a41d149f074a378b881" + "1500ce68a9fe5cec25a59273e7519f34c4458d70911714f1819aa46fbe143934c933ae6dec0fb124" + "59970695020000000d3c723b91adb0da7c4aa7e7eb5a15bcde035fb9a9fe1fd84cc43c510385b9a4" + "c2aac1d67a909b297c703915312e9c3c5a06c40b20ea99d5078a806d020000008bbfc9723107f3f5" + "b2cd3dbddc74e26de905e48da9feb0313e7f8933e315130fa9a84c8288f83f6e70b1646d8026e9f1" + "704f1b16286ba2da72437f9b01000000ec9e71ee4b951507beb42b3473cef00e89015f24a9fe2333" + "02ad3b82d639272e0046eadfbd2146bf8cfdb205f90e54b58a6ee136a779f37c0d58fbcc01000000" + "d0d44ff1e51c35157666c05348e6f507ff01e898a9fe9510b900b2061d0c334b009f2dd1cdf64b0f" + "9a60e0e289f08db3e4bafc4e095a3230b4d9e89b010000006855676c277cf1bd017c9148da5892bb" + "4903c3a7a9fe689d3391ce7d3fd48469005f0c233dbdd2a97835df1f1782dee88487fd0db5971b46" + "9d82c85601000000050f63f8282f3464443cacf59c6379a44b0392f4a9fea98cb121c19c69d9942f" + "000bcea75481f25e307d0de9a7afe283bd2f22ead05ff72045aaf95e01000000b9ef1b2110613fc9" + "f90adac616a31dc2e4002345a9fe7151b38fc9c909cf8d71e64b0bd761fdf274fc5dca8ce1bd1871" + "ae17bb451585609236ba0c700100000040318db913a353edc66efc068829c0e66a17143aa9feefb4" + "6b382ab0404cdf029a6ce5d906837dbca6a5ee19d6f63fe9cbdd01f7246f13b2050424a200000000" + "a029c896b4132bd895072cfeffe9d6812200bb02a9fe259b173c333cd03bc90500b899afeb760e3f" + "004a2efc8ffc96b89b1bc8f415bd4e77c7a4c65600000000cd625009a40aeb62a42b6a62548e3c38" + "b9022002a9fec5fbfaf1809becd2506300a6da29b2e94d3ab51fe0e9af98b180a36035fb6297dfa7" + "0e09e2fc00000000cc807cdce682f80f94315c45ef817264c802736ea9fed637b077ddad3108be69" + "f9b97d05c917ad6b10e693bb6e26f2ba90c8e909e85e20e591bf821c00000000c37ff4283a631480" + "91acc42cac4ef3ad3702fec7a9fe62475588456e4ead7cbda620a3abae816e34cba1d74f18d1c4ed" + "b99c0e49bcb946f71a64192d000000005eb888e9eb37bb046686943b101e1f553203abf8a9fe17c3" + "641e447514ca565fb9b68c08a5e4351ea349e1ccf662e058b879a45176740744a19da86c00000000" + "548759d313a5b92de36f90d4bc8b496afd03fe47a9fe370b6ec6584d64496089570968ead4d1ae91" + "c819bb068196d599efde3246e43f5e7934f0386a000000004064f6b021281e235f94ae20ac26c7d4" + "1f0350bfa9fe055bcfe3756ccdb3455c60ca7b11c66af76e80f062ea1a7e0b7be218d067530e1b04"), + [1] = ("4d9ca9d20300000074e786047d8683facd7db68b9ae586dacd0b070c50320427c4dd3d031e33f22c" + "636360d696be085aad7c499dd538d34574c038404923e75d30d2c50503000000210aeb0934cb2a24" + "7000b96d06992b6a5875d3995b9663d2df48f333ef467092818aa77d6732b678cf844ef5a943825f" + "cd743f59bd14c89bdf6f628a02000000f25d5895fb57fa60d9279fb2b8fcbac6ab6674f7a6df7979" + "f6989d2d6a909e986ff7add5df2c93e05459507b5d8c6a0f466554d2ae4d52a8de485b1301000000" + "957c22721583c453d15ade4386ffd00b36518589be395312f09e601d88d4cb0c2f4d15c69e89f94e" + "f7b30486591030639eb0e99f7f53702fa4bab14801000000e6aae816430607ca0675e09818e9bbec" + "5966c59068baf76ab08940f6fc3bbdc7f6090f756aae660b3b02239efc1fb23d24438387def0f4c6" + "36ba0c700000000040318db913a353edc66efc068829c0e66a32143a0554efb46b382ab0404cdf02" + "9a6ce5d906837dbca6a5ee19d6f63fe9cbdd01f7246f13b254270e46000000006a894e387625da37" + "6feecb80ac245409c06bcc271d9c2f67179bff0644399ae79c64ed0432d599eaa660ac824b7fae38" + "9861419c50da49bf5cfd5ce600000000152f2b70eaef7443e0f79ab6902dde53362fec7127e19f25" + "4ac9588319558041fc62ed564153e17478f8c3344d89c0bb5408c1b7d17fb084b16c737600000000" + "5219061ab4c5c79489b2cc6a883c14697280cb8b5adac8f5e6d66df46ea139107754dee62c36d2fc" + "70ccc567df7a49b8a4c73cf5ffa4ffc83722d9b7000000001fb7c8307f06b4b29088f20d9ac676d5" + "5b2dea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218424e48836dd1cb504e03d53e1124c5" + "87bb24e500000000e9cf9f6df9615189f78ee815b2781ea55c5f55876b6a3f13922b6cb8360feaac" + "1d5c302df59dd32a677e5a3af4fe297f608df061d45d864d348352d7000000001ea012e5307294b6" + "e346dac428ab20075e11e38dd16f8ee4ccd2f50c30706cae3fdcc2f0ee3d5e2612ea3b95e1d2a5d0" + "fb95e8332fdfff65fa3abc1e0200000075a2f42b50c6a36340132378b95c59313b58ba64dbe99620" + "69e66142e22753344fda8a3e0b841cf76391dd68269b53eccb44a831714acfb5f32099a800000000" + "4d4647f53b1921af0f88e3759a08e7a56655861efedbf42ccd3c72f2ad063857ca82ac5180101be4" + "f85cef468ea086ea9aaafdc388811ec7c442139803000000cee64b38b56e03e0f121014a2f70249e" + "ef217bcefeec856e3973dc42a1003be94f89d8eeb1f14d985d5bbe6c10085f3d6176f78a19bb8df1" + "09f4ecf100000000a1c748288ae21e371051852c972ea7954066884afed7b044fd13a6826a4c619f" + "9037d7a754655354c47cf0f551e96770a754ac19ef820fe0732d803e000000001a0dd8c052ed6b13" + "e2815a1a37a52bddd109f101fed87eed72bb58f0e9201f17bd99fcf72909ac9e7a55299e9bb4fd53" + "bc7417940fcffe3feafb1ac4020000003aa9986700b2a2b3ed257b8b0489f48f055ac8cafea105b3" + "27335a25a364d1015ffac03089f45539e1b0178462156cd6b83579b8da27345a544e4b2700000000" + "a7f810d249adc17647176b7c07d856e3b87befebfe9dd9d61966b7ae7412041de5fe7d361f2d5dfd" + "66a3ae3939762df33a2d55060c78d551dd65aeb202000000902383028e3b47f2111d891d9f3c2c88" + "cd1676190000000000000000000000000000000162c12fba5b1cdec48d10bbb13b8313d8cd2a24d3" + "27c219630100000054830c68e44ea74b4f2b83f9b3bee14d866e4c9e000000000000000000000000" + "0000000101883918039249f398f9b37ea0914651b2a16e64a19da86c64fefab2548759d313a5b92d" + "e36f90d4bc8b496afd57fe4700000000000000000000000000000000d4d1ae91c819bb068196d599" + "efde3246e43f5e79507e308d030000008dab2dade2ab2fc9c56a7c86be5f96228e05f2f400000000" + "000000000000000000000000cb2c354434819f4b248eb2b8e3ff1a5ffc386da38483a2d003000000" + "8ed3481e0bccc460e89f7abdb682380a6208e37400000000000000000000000000000000bae87d60" + "e00473755d31e5b2de252167c1c91b3a87e6f7bb03000000e612098610e52bb2a16a4008aefd545b" + "7a219db500000000000000000000000000000000f769bb295766ed37a2123c5b6a813387e99bb834" + "bc7ef08203000000ef60a8b540b26f66761d1f13badfad0fe8178f3c000000000000000000000000" + "00000000329f997184c9d2578e4cf9c48147507e1cd59ea13f81268103000000585287dc6ca972a2" + "cfb18b2b2cb749e2e022544d00000000000000000000000000000000ddd3aa9ba511d2e40edb4d75" + "8fb554158ae5c7c09d82c85602000000050f63f8282f3464443cacf59c6379a44b8092f400000000" + "0000000000000000000000005481f25e307d0de9a7afe283bd2f22ead05ff72045aaf95e02000000" + "b9ef1b2110613fc9f90adac616a31dc2e44923450000000000000000000000000000000061fdf274" + "fc5dca8ce1bd1871ae17bb4515856092cbb110fd02000000b9aca07b6e4925dd27943a272c171ed1" + "5a66be1c0000000000000000000000000000000002a1f8e6f5657f3f9e3eb807cbad76451055edb8" + "5f5b481b0100000068cb3bc873b04d937a6ed8f7bc51e5406674d098000000000000000000000000" + "000000007799416af1f0a086fbd7e2f7dea0077ae9c0c0d9ecc8fb1101000000fcebbaeb0c565359" + "23f14874042a8aff1d008e5e0000000000000000000000000000000064a2827b7cdd38d0314c178e" + "925b568ae56bc4e9438a72e1000000002495a609675344f7e2e3a5ebaec3c85f0a5742f700000000" + "000000000000000000000000bf085387046ef8a36f0e9e6982d15956ec2e2924891715df00000000" + "edae579e2e10c7f7a22ba0340436242cbe53248c000000000000000000000000000000006712dfb4" + "d184e820a28fa772a19cdf6dd1c173f6e45aaf610000000040125e6baf4648cbaaa37b861e6d46da" + "fe556ec4000000000000000000000000000000008a06e2c9cb29efdf672d2fa57fc85ebbe276c566" + "8c45eb5003000000562dcd24a27c8212127da516b1091d1d4f5f0817000000000000000000000000" + "00000000fe917423d314ae73572ff808b373f5b193d661edbe46bae5030000006665a268abfe8a41" + "d149f074a378b8811526ce6800000000000000000000000000000000911714f1819aa46fbe143934" + "c933ae6dec0fb124fcd32a7f0300000023a5223a2fb2c0764e08db62a3db07d0907360b900000000" + "000000000000000000000000b0ed3a7d0f8b13cd736aaa72021a381fb50e2c421dff045203000000" + "36674cdefb57b9ae54cfe8f42bf0e9381b04c43900000000000000000000000000000000eb720c4a" + "e3c9472e5f2da5d9c5cfd9f2343b21363c84c4eb0200000087780281d47a32f2235376239daeaacb" + "3c54864b00000000000000000000000000000000db544e44df2d7c2790d3119a051bb2ee8192ac0c" + "804c122f0100000059747cf23a1349c8ab2dadc5a39411fd4f60116d000000000000000000000000" + "00000000a7ae8ff040483e310819e3b10db116431ec6f76987b8c3b9010000008982c42f53700a34" + "37c5156e072b2f2fb372c9cf00000000000000000000000000000000df1424ce3ee1d76fc1ea76e9" + "8c9dfc78997ab53ef9531cd901000000d241989477a363d55ad47b8a11090df8da18d88d00000000" + "0000000000000000000000004b15e2ae496ad01bf007eacb0a28aec86828251065dbc8a900000000" + "b550c5db56189572f32f4af595d785d5c10eaad40000000000000000000000000000000066ec305a" + "225a0c71b2ce78bb16104c8eaf18c56557d6249b000000007dc7f17f666969e45c3baf7a119a65ee" + "0b34fa9e00000000000000000000000000000000b314f695bd82e9ea8891ed0a3d1b91caae8cb60b" + "fcb6a035000000009726d80d9c2d89df765b4d9a130257dc5f2bf03a000000000000000000000000" + "00000000fd338f357e75f8ce6e8cc34573654ea6624f138e91bf821c03000000c37ff4283a631480" + "91acc42cac4ef3ad373bfec700000000000000000000000000000002ae816e34cba1d74f18d1c4ed" + "b99c0e49bcb946f734f0386a010000004064f6b021281e235f94ae20ac26c7d41f2a50bf00000000" + "000000000000000000000002c66af76e80f062ea1a7e0b7be218d067530e1b04c386e9c601000000" + "10ee58bdc75183609985d627b6a4b1cbe413cbbb00000000000000000000000000000002463f9b83" + "06c83bc0269779114bdade862c224f6f1a64192d010000005eb888e9eb37bb046686943b101e1f55" + "3273abf800000000000000000000000000000002a5e4351ea349e1ccf662e058b879a45176740744" + "32d1d5f503000000bf7a70ba5193a162bc92ec1b11d9172cf83a0347000000000000000000000000" + "00000002b887edcd61c2f5d2f381f843b809d259e499db7dfde69eec01000000bd68ab722af14548" + "b29572e504265f6c726d3e2200000000000000000000ffffdb46a54cadb245eafde6b02567f814de" + "39dd8f88152a584562fb81e702000000ca7feefe1933631e8e69f6d9d6962d2c6e5804f57239c09c" + "47150b9b14010469823acb72bb89182f931121966e91b9153b36bc60be5b534e6e8e99cd01000000" + "644f0e8ab3121cd5ef51e696c816290dba040e7726d082e1530ff5397c9125f59577d71c4b258a00" + "5116d11354edff62ceaa458fc75a91c4b4d9e89b010000006855676c277cf1bd017c9148da5892bb" + "4945c3a7ed55689d3391ce7d3fd48469845f0c233dbdd2a97835df1f1782dee88487fd0db5971b46" + "2c19a0920000000092defa453a3efc240b9977e166bee737fe1c670c439a644c323b59b4cd20eb7d" + "d3d38785c88ffad45e0dfe491d1ba96742c7b5e02b227122ab90135f0300000064d210a256be75e0" + "509c4477d19ac64b2e64220d6c0fc09c25d6534c809829af4a9df58dbfef186d416f3a1ef170d10f" + "2c932e655203d82a59970695030000000d3c723b91adb0da7c4aa7e7eb5a15bcde525fb98b841fd8" + "4cc43c510385b9a4c2aac1d67a909b297c703915312e9c3c5a06c40b20ea99d58c3b371502000000" + "710c030690f5f18ea125dbf7d7e93bd65c03a56dfdcfc1155f236c8b9c79a6205f660bbf024b03ff" + "0a8e27c405e6424457393c6fd7ac5f9940e55b8b01000000c0cfb2b4386bec092fa5757ecde9348b" + "da4c2ebd4f78a6aa667224dae775e5ccd141aca2ff0f576767d3648102b61886b62f22ca33478e1f" + "abf85f0c0100000008d33a2ea67776d7f88d69c8c7e3b2d3c954f054e93f8120abb42316c533d9c9" + "4d88189c471a1ff2f0ce3ff66e782110125ae2ed74993adeae6da48b00000000bcfe97e1761e1245" + "7ad742d3d7320a4f8815f47f5dd0cf69cb22840f09b3fe7749509cb6752b2cee30b7e7736a0afc98" + "79ea40e69710fc9f0408423e00000000886dc91e2e5b0f0b65843fc961f7ad18014c3c67d9714f19" + "f1e41c073164d93b1171719c7f81773302d007c983566139c695e0f4b661ee6bc896c9a703000000" + "0a5f6abd850b06e3d9662795ce2cc1cee00802abfec2aaa218dc091e9aa1477f6fdc9830d7fbc958" + "29a8838314dff34d24c332219a1b163a3bbfb50103000000df6b3542f4bb5f574c5cf8107ba282f4" + "f9188219fef93e742d08f0550b55726f2292362e5d68265d9f98c82d9b7a559be3acf4fc36fa6b51" + "c8f1853b030000000e2b00b667b7b16dae02dfa0c26e7c3add113bd3febfa0f02f2f3313d8469d09" + "a92409c0b7f0318a575a4f8e061db3dd7fde25654a4059d5b442548601000000b0216050ed7afd74" + "1024e8365ea1aa11f92797c0feac468e9de5a9caf493472201e48d163106cc397446a33fdc335c8b" + "152c507a0a3c8e7cacdca10f01000000a36b178aabc78a4a0d80684ee5dbf45bba3010fbfeb3cc24" + "904f288262e6ea77a22fa5f863eaeefa701d120523bd98f29b098b43cd68be6e37c27c1500000000" + "7e5c53e755c90fa09e9653ddcb1b14d2757f8a13feac3c1734b49e955cbcf46d256a1818053da43e" + "c5085d1df74d1e287271092897e2625103e0b1b10100000090a2312e17f1a35900459582f4ef43c7" + "807b887200000000000000000000000000000001e94030b34774d1d7dddedd9899f0f627be16965a" + "87bc45db0100000036bd39a44e8e8bc17c01ac63eca0c1cfbb4f4132000000000000000000000000" + "00000001eca6d1adaccae11f8045a80f855ebf3b772eb2b1449a774903000000ec852d59f3d17232" + "edd86ad6c3103a68844c9aef00000000000000000000000000000001599364e13468f80fd514573f" + "b572671cf6932f69d9e1825f03000000284a024b7f9e85ff73e050a2cd89fd276e0acb8800000000" + "000000000000000000000001129cdc690fcc00ac2daa755e5292cd32dc096cd572437f9b02000000" + "ec9e71ee4b951507beb42b3473cef00e896b5f2400000000000000000000000000000001bd2146bf" + "8cfdb205f90e54b58a6ee136a779f37c2931f2d30300000050b8d10ab700cc3a7cf51be0403b654b" + "a242680800000000000000000000000000000000a6bdc8789cf851782d895bcc8da98489c55b8c12" + "37686b5e030000006215de4bb6f6f3d031a790287e45e9c18b7136c0000000000000000000000000" + "00000000ec7d3abc4ccf30d3aaaf02a4f05d7308b67f91bfc7a4c65603000000cd625009a40aeb62" + "a42b6a62548e3c38b96a200200000000000000000000000000000000b2e94d3ab51fe0e9af98b180" + "a36035fb6297dfa78704133102000000d9b4e3ce848518c4e3f6cbf25e5e1b990f13676700000000" + "000000000000000000000000690807d52617369ee1af4ca5a6a95581af5fd7ceb7a350f902000000" + "fa7db4532545666937c22a3b6e9686dcc43ccbee000000000000000000000000000000006ba04f14" + "6e4c699341b95f41d9c1e67743efb54e3cf09e8b01000000e79c10acfce165e332a62384ec04e5ba" + "b46785ad00000000000000000000000000000000f86c260a9edfa7a74c1c83c18e47935e8354846e" + "4fc812bd010000006d064126666befbb98c39e7cc282208fef4a7ff4000000000000000000000000" + "00000000add1c86e759d0c90bc512e137dcef5e4a27985bdd8a4c5cf01000000fcc2056cc1ff8e51" + "bbce426cfa4b861cc73992be000000000000000000000000000000000aa20624fbab244735d67c61" + "283031667b2d74a10d58fbcc01000000d0d44ff1e51c35157666c05348e6f507ff72e89800000000" + "000000000000000000000000cdf64b0f9a60e0e289f08db3e4bafc4e095a32302b09258301000000" + "9f9f0251becc987907879cca68fec7bbbb4d8edf0000000000000000000000000000000016772167" + "3f2b02b3256ead1f2fea9bc12f0cfca1078a806d000000008bbfc9723107f3f5b2cd3dbddc74e26d" + "e956e48d0000000000000000000000000000000088f83f6e70b1646d8026e9f1704f1b16286ba2da" + "0a6527f600000000aca0c7ee4197338581cafd63e66e3a23d6572578000000000000000000000000" + "000000009052c22b9f3c39f24b0572b1de745cb25851429b8c54dda900000000d43e6505621b9a7f" + "0422ae3fc8979ee0c400d79400000000000000000000000000000000414d94d0e02d2ec587fc3300" + "03781b0f294a2b73050424a203000000a029c896b4132bd895072cfeffe9d6812232bb0200000000" + "000000000000000000000000eb760e3f004a2efc8ffc96b89b1bc8f415bd4e77d611d7b103000000" + "f9f23b5f1570a4648a0ff80dd9a37a82e10c20aa00000000000000000000000000000000de6f36d6" + "64873c5be82c5361358730bcde43782df264af6703000000c38b6b8ee2614344bea73223e59bf019" + "345ae9fa000000000000000000000000000000009d80ab132e1ac921eb76adbb229df32e561fa80a" + "49ba9be3020000000c67c3d4afa9c8649da90bd2fff2f2568108870b000000000000000000000000" + "00000000d1111b067acbce3e3bcdf3824f1b134847ff26ba0e09e2fc01000000cc807cdce682f80f" + "94315c45ef817264c83c736e00000000000000000000000000000000c917ad6b10e693bb6e26f2ba" + "90c8e909e85e20e5182c028701000000ec4501a1e27acfee7a8588ffd5a06cae4228e59500000000" + "000000000000000000000000dda0b6ead1e1b34901eaedd5bcd7be07d78e62229427c22601000000" + "86ed27184b443181a5edc511c1507a141e4a5156000000000000000000000000000000009870ccec" + "3def0ad92749e016663fe6ee0228c1da1539ce410000000018238487a417f3da01d99dae5f190096" + "cc292cab00000000000000000000000000000000d8fbe9a4fdb3d117d76b0de5416f95e7bb75d72f" + "b60291ea00000000def85b75827b26e8a0bef8675b29a197b71bccea000000000000000000000000" + "000000004a503a712350acbd48411f0dc15d2f0f49dad3458d1e69c801000000b973972c17a47631" + "c169f11ff9119c40b47cb66300000000000000000000000000000002ea4a849f060ddf57b24a5be9" + "b10123e6e4f15ecdc67b2e48000000001785d3ffdbd9a617857ae8126b028c0e3e4b535400000000" + "000000000000000000000002a84035b632ef3be6070dafa202187470e9da55709c88b02a02000000" + "04b0595daf37deb499996bfb667f072dec2c5d9c00000000000000000000ffff99d90a8543961b2c" + "cd47724a3c460ba85183f4c5daae7d6336506ebd00000000ef369bb8ebfdcec3f8c8fa6867a982be" + "8a534f8500000000000000000000ffffe8d07c84965a316af2abb982b001ec16901f55f960c55c22"), + [2] = ("df6f628a02000000f25d5895fb57fa60d9279fb2b8fcbac6ab6674f7a6df7979f6989d2d6a909e98" + "6ff7add5df2c93e05459507b5d8c6a0f466554d2ae4d52a8fa3abc1e0200000075a2f42b50c6a363" + "40132378b95c59313b58ba64dbe9962069e66142e22753344fda8a3e0b841cf76391dd68269b53ec" + "cb44a831714acfb554270e46000000006a894e387625da376feecb80ac245409c06bcc271d9c2f67" + "179bff0644399ae79c64ed0432d599eaa660ac824b7fae389861419c50da49bfb16c737600000000" + "5219061ab4c5c79489b2cc6a883c14697280cb8b5adac8f5e6d66df46ea139107754dee62c36d2fc" + "70ccc567df7a49b8a4c73cf5ffa4ffc83722d9b7000000001fb7c8307f06b4b29088f20d9ac676d5" + "5b2dea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218424e48836dd1cb504e03d53e1124c5" + "87bb24e500000000e9cf9f6df9615189f78ee815b2781ea55c5f55876b6a3f13922b6cb8360feaac" + "1d5c302df59dd32a677e5a3af4fe297f608df061d45d864d4d9ca9d20300000074e786047d8683fa" + "cd7db68b9ae586dacd0b070c50320427c4dd3d031e33f22c636360d696be085aad7c499dd538d345" + "74c038404923e75d30d2c50503000000210aeb0934cb2a247000b96d06992b6a5875d3995b9663d2" + "df48f333ef467092818aa77d6732b678cf844ef5a943825fcd743f59bd14c89bde485b1301000000" + "957c22721583c453d15ade4386ffd00b36518589be395312f09e601d88d4cb0c2f4d15c69e89f94e" + "f7b30486591030639eb0e99f7f53702fa4bab14801000000e6aae816430607ca0675e09818e9bbec" + "5966c59068baf76ab08940f6fc3bbdc7f6090f756aae660b3b02239efc1fb23d24438387def0f4c6" + "36ba0c700000000040318db913a353edc66efc068829c0e66a32143a0554efb46b382ab0404cdf02" + "9a6ce5d906837dbca6a5ee19d6f63fe9cbdd01f7246f13b25cfd5ce600000000152f2b70eaef7443" + "e0f79ab6902dde53362fec7127e19f254ac9588319558041fc62ed564153e17478f8c3344d89c0bb" + "5408c1b7d17fb084348352d7000000001ea012e5307294b6e346dac428ab20075e11e38dd16f8ee4" + "ccd2f50c30706cae3fdcc2f0ee3d5e2612ea3b95e1d2a5d0fb95e8332fdfff65c442139803000000" + "cee64b38b56e03e0f121014a2f70249eef217bcefeec856e3973dc42a1003be94f89d8eeb1f14d98" + "5d5bbe6c10085f3d6176f78a19bb8df109f4ecf100000000a1c748288ae21e371051852c972ea795" + "4066884afed7b044fd13a6826a4c619f9037d7a754655354c47cf0f551e96770a754ac19ef820fe0" + "f32099a8000000004d4647f53b1921af0f88e3759a08e7a56655861efedbf42ccd3c72f2ad063857" + "ca82ac5180101be4f85cef468ea086ea9aaafdc388811ec7732d803e000000001a0dd8c052ed6b13" + "e2815a1a37a52bddd109f101fed87eed72bb58f0e9201f17bd99fcf72909ac9e7a55299e9bb4fd53" + "bc7417940fcffe3f544e4b2700000000a7f810d249adc17647176b7c07d856e3b87befebfe9dd9d6" + "1966b7ae7412041de5fe7d361f2d5dfd66a3ae3939762df33a2d55060c78d551eafb1ac402000000" + "3aa9986700b2a2b3ed257b8b0489f48f055ac8cafea105b327335a25a364d1015ffac03089f45539" + "e1b0178462156cd6b83579b8da27345add65aeb202000000902383028e3b47f2111d891d9f3c2c88" + "cd1676190000000000000000000000000000000162c12fba5b1cdec48d10bbb13b8313d8cd2a24d3" + "27c219630100000054830c68e44ea74b4f2b83f9b3bee14d866e4c9e000000000000000000000000" + "0000000101883918039249f398f9b37ea0914651b2a16e648483a2d0030000008ed3481e0bccc460" + "e89f7abdb682380a6208e37400000000000000000000000000000000bae87d60e00473755d31e5b2" + "de252167c1c91b3a8c45eb5003000000562dcd24a27c8212127da516b1091d1d4f5f081700000000" + "000000000000000000000000fe917423d314ae73572ff808b373f5b193d661edbe46bae503000000" + "6665a268abfe8a41d149f074a378b8811526ce6800000000000000000000000000000000911714f1" + "819aa46fbe143934c933ae6dec0fb124fcd32a7f0300000023a5223a2fb2c0764e08db62a3db07d0" + "907360b900000000000000000000000000000000b0ed3a7d0f8b13cd736aaa72021a381fb50e2c42" + "1dff04520300000036674cdefb57b9ae54cfe8f42bf0e9381b04c439000000000000000000000000" + "00000000eb720c4ae3c9472e5f2da5d9c5cfd9f2343b21363c84c4eb0200000087780281d47a32f2" + "235376239daeaacb3c54864b00000000000000000000000000000000db544e44df2d7c2790d3119a" + "051bb2ee8192ac0c804c122f0100000059747cf23a1349c8ab2dadc5a39411fd4f60116d00000000" + "000000000000000000000000a7ae8ff040483e310819e3b10db116431ec6f76987b8c3b901000000" + "8982c42f53700a3437c5156e072b2f2fb372c9cf00000000000000000000000000000000df1424ce" + "3ee1d76fc1ea76e98c9dfc78997ab53eecc8fb1101000000fcebbaeb0c56535923f14874042a8aff" + "1d008e5e0000000000000000000000000000000064a2827b7cdd38d0314c178e925b568ae56bc4e9" + "f9531cd901000000d241989477a363d55ad47b8a11090df8da18d88d000000000000000000000000" + "000000004b15e2ae496ad01bf007eacb0a28aec86828251065dbc8a900000000b550c5db56189572" + "f32f4af595d785d5c10eaad40000000000000000000000000000000066ec305a225a0c71b2ce78bb" + "16104c8eaf18c56557d6249b000000007dc7f17f666969e45c3baf7a119a65ee0b34fa9e00000000" + "000000000000000000000000b314f695bd82e9ea8891ed0a3d1b91caae8cb60b891715df00000000" + "edae579e2e10c7f7a22ba0340436242cbe53248c000000000000000000000000000000006712dfb4" + "d184e820a28fa772a19cdf6dd1c173f6fcb6a035000000009726d80d9c2d89df765b4d9a130257dc" + "5f2bf03a00000000000000000000000000000000fd338f357e75f8ce6e8cc34573654ea6624f138e" + "a19da86c64fefab2548759d313a5b92de36f90d4bc8b496afd57fe47000000000000000000000000" + "00000000d4d1ae91c819bb068196d599efde3246e43f5e79507e308d030000008dab2dade2ab2fc9" + "c56a7c86be5f96228e05f2f400000000000000000000000000000000cb2c354434819f4b248eb2b8" + "e3ff1a5ffc386da387e6f7bb03000000e612098610e52bb2a16a4008aefd545b7a219db500000000" + "000000000000000000000000f769bb295766ed37a2123c5b6a813387e99bb834bc7ef08203000000" + "ef60a8b540b26f66761d1f13badfad0fe8178f3c00000000000000000000000000000000329f9971" + "84c9d2578e4cf9c48147507e1cd59ea13f81268103000000585287dc6ca972a2cfb18b2b2cb749e2" + "e022544d00000000000000000000000000000000ddd3aa9ba511d2e40edb4d758fb554158ae5c7c0" + "9d82c85602000000050f63f8282f3464443cacf59c6379a44b8092f4000000000000000000000000" + "000000005481f25e307d0de9a7afe283bd2f22ead05ff72045aaf95e02000000b9ef1b2110613fc9" + "f90adac616a31dc2e44923450000000000000000000000000000000061fdf274fc5dca8ce1bd1871" + "ae17bb4515856092cbb110fd02000000b9aca07b6e4925dd27943a272c171ed15a66be1c00000000" + "00000000000000000000000002a1f8e6f5657f3f9e3eb807cbad76451055edb85f5b481b01000000" + "68cb3bc873b04d937a6ed8f7bc51e5406674d098000000000000000000000000000000007799416a" + "f1f0a086fbd7e2f7dea0077ae9c0c0d9438a72e1000000002495a609675344f7e2e3a5ebaec3c85f" + "0a5742f700000000000000000000000000000000bf085387046ef8a36f0e9e6982d15956ec2e2924" + "e45aaf610000000040125e6baf4648cbaaa37b861e6d46dafe556ec4000000000000000000000000" + "000000008a06e2c9cb29efdf672d2fa57fc85ebbe276c56691bf821c03000000c37ff4283a631480" + "91acc42cac4ef3ad373bfec700000000000000000000000000000002ae816e34cba1d74f18d1c4ed" + "b99c0e49bcb946f732d1d5f503000000bf7a70ba5193a162bc92ec1b11d9172cf83a034700000000" + "000000000000000000000002b887edcd61c2f5d2f381f843b809d259e499db7d34f0386a01000000" + "4064f6b021281e235f94ae20ac26c7d41f2a50bf00000000000000000000000000000002c66af76e" + "80f062ea1a7e0b7be218d067530e1b04c386e9c60100000010ee58bdc75183609985d627b6a4b1cb" + "e413cbbb00000000000000000000000000000002463f9b8306c83bc0269779114bdade862c224f6f" + "1a64192d010000005eb888e9eb37bb046686943b101e1f553273abf8000000000000000000000000" + "00000002a5e4351ea349e1ccf662e058b879a45176740744fde69eec01000000bd68ab722af14548" + "b29572e504265f6c726d3e2200000000000000000000ffffdb46a54cadb245eafde6b02567f814de" + "39dd8f88152a5845ab90135f0300000064d210a256be75e0509c4477d19ac64b2e64220d6c0fc09c" + "25d6534c809829af4a9df58dbfef186d416f3a1ef170d10f2c932e655203d82a5997069503000000" + "0d3c723b91adb0da7c4aa7e7eb5a15bcde525fb98b841fd84cc43c510385b9a4c2aac1d67a909b29" + "7c703915312e9c3c5a06c40b20ea99d562fb81e702000000ca7feefe1933631e8e69f6d9d6962d2c" + "6e5804f57239c09c47150b9b14010469823acb72bb89182f931121966e91b9153b36bc60be5b534e" "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c03a56dfdcfc1155f236c8b9c79a620" - "5f660bbf024b03ff0a8e27c405e6424457393c6fdac12ebd01000000667224dae775e5ccd141aca2" - "ff0f57676754648102b61886b62f22ca33478e1f891715df7fc6a902edae579e2e10c7f7a22ba034" - "abf85f0c0100000008d33a2ea67776d7f88d69c8c7e3b2d3c951f054e93f8120abb42316c533d9c9" - "4d88189c471a1ff2f0ce3ff66e782110125ae2eddaae7d6300000000c0982b283aa9986700b2a2b3" - "ed257b8b042ff48f053ec8cac72105b327335a25a364d1015ffac03089f45539e1b0178462156cd6" - "6855676c00000000017c9148da5892bb4951c3a7ed55689d336bce7d3fd48469845f0c233dbdd2a9" - "7835df1f1782dee88487fd0db5971b46b7a350f998c39e7c00000000efc57ff447036b9551adcb22" - "fd50793f791c3c7dadd1c86e759d0c90bc512e137dcef5e4a27985bd8d1e69c83dc21056b973972c" - "bc51e540030000006c3d048a92d3adc69a84eb47622400207708416afef0a086fbd7e2f7dea0077a" - "e9c0c0d9c386e9c6e6a2cbfa10ee58bdc75183600422ae3f03000000c43bd794c697895e5bfe47c6" - "f53a54e01b211d89fecd94d0e02d2ec587fc330003781b0f294a2b73c4421398f4de67e9cee64b38" - "69121aec010000000fcc00ac2daa755e5292cd32dc096cd5d830c5cffe91ee1cfcc2056cc1ff8e51" - "bbce426cfa4b861cc78592be7b14e7ba9c15acb836674cde0200000054cfe8f42bf0e9381ba2c439" - "6de60f032b5af34dfe959871c0d4c0d4eb720c4ae3c9472e5f2da5d9c5cfd9f2343b21362c19a092" - "b2cd3dbd01000000e958e48d2ab8b0313e7f8933e315130fa9274c82feb83f6e70b1646d8026e9f1" - "704f1b16286ba2dabc7ef0820c91ed33ef60a8b5bcfe97e1000000007ad742d3d7320a4f880cf47f" - "5dd0cf69cb7f840ffeb3fe7749509cb6752b2cee30b7e7736a0afc9879ea40e69710fc9f6e8e99cd" - "1dce2f83020000003a3efc240b9977e166bee737fe73670c436b644c000000000000000000000000" - "000000015e0dfe491d1ba96742c7b5e02b227122cf844ef501000000cd743f59bd14c89b5cfd5ce6" - "e82e7854157b2b700000000000000000000000000000000127e19f254ac9588319558041fc62ed56" - "b83579b80300000072437f9b6245de39ec9e71ee4b951507be0a2b34000000000000000000000000" - "00000001d639272e4a46eadfbd2146bf8cfdb205b3980deb020000006c1de913df1424ce3ee1d76f" - "c1ea76e98c16fc7800000000000000000000000000000001e44ea74b4f2b83f9b3bee14d861a4c9e" - "0436242c03000000ee3fbc164632d4f28aa28c08f80dd50c6705dfb4000000000000000000000000" - "00000000078a806d329c9b008bbfc9723107f3f52af145480300000004265f6c72923e22594f3f79" - "e208ed2e2e7107710000000000000000000000000000000039dd8f88152a58454d9ca9d20f45dfa7" - "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f6042f061000000000000000000000000" - "000000008ae21e371051852c972ea7954079884a9a1b163a030000000e2f4f911a0dd8c052ed6b13" - "e2815a1a37322bdd00000000000000000000000000000000bd99fcf72909ac9e7a55299e9bb4fd53" - "9f3c2c8803000000f51f44e644d7cf1d06b2b115d882549e62042fba000000000000000000000000" - "000000004fc812bd2f8a59d96d064126666befbbf257b044030000006a4c619f9037d7a754655354" - "c47cf0f5512167700000000000000000000000000000000050b8d10ab700cc3a7cf51be0403b654b" - "74e7860402000000cd7db68b9ae586dacdb4070c50320427c4803d03000000000000000000000000" - "00000000d538d34574c038404923e75d0e09e2fcfc1519de010000002545666937c22a3b6e9686dc" - "c405cbee504dc252000000000000000000000000000000006e4c699341b95f41d9c1e67743efb54e" - "6aae660b01000000fc1fb23d24438387def0f4c6544e4b275d4a7146000000000000000000000000" - "00000000b883efebc09dd9d61966b7ae7412041dd7ac5f9901000000822a272bec4501a1e27acfee" - "7a8588ffd5286cae0000000000000000000000000000000077a47579dda0b6ead1e1b34901eaedd5" - "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e0e00b6000000000000000000000000" - "000000005e7fa0f02f2f3313d8469d09a92409c0b4d54acb00000000a417f3da01d99dae5f190096" - "cc582cabd534d15a00000000000000000000000000000000fdb3d117d76b0de5416f95e7bb75d72f" - "fc2b445700000000496ad01bf007eacb0a28aec868282510b61b91ea000000000000000000000000" - "000000005b29a197b7b3cceaf5f1bb12c535256a74993ade03000000e62112898dab2dade2ab2fc9" - "c56a7c86be73962200000000000000000000000000000000bdd06352cb2c354434819f4b248eb2b8" - "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a0c1480000000000000000000000000" - "000000005588456e4ead7cbda620a3abae816e34e3ff1a5f03000000b4425486c619147eb0216050" - "ed7afd74105fe83600000000000000000000000000000000f493472201e48d163106cc397446a33f" - "bc74179403000000438a72e12ae0436a2495a609675344f7e226a5eb000000000000000000000000" - "0000000061eda239d9d083c3bf085387046ef8a34153e174020000004d89c0bb5408c1b7d17fb084" - "d9e1825fa613e1af000000000000000000000000000000006e08cb887464b9344ec3127c750fabdd" - "6c0fc09c02000000809829af4a9df58dbfef186d416f3a1ef154d10f000000000000000000000000" - "0000000087780281d47a32f2235376239daeaacba9a89f8701000000fcdf6d9be94030b34774d1d7" - "dddedd989972f62700000000000000000000000000000000848518c4e3f6cbf25e5e1b990fc46767" - "fd338f35010000006e8cc34573654ea6624f138ef9531cd9361802e4000000000000000000000000" - "00000000da40d88d40a6d75bc404156225b7eede2cb749e2010000000eb4f73e75039fcf251b32fc" - "79685b05dd3caa9b000000000000000000000000000000000d58fbcc58fc4c2fd0d44ff1e51c3515" - "b7f0318a01000000061db3dd7fde25654a4059d565dbc8a91e004457000000000000000000000000" - "00000000c1b5aad487c192f08bd7a09bdd21444359747cf200000000ab2dadc5a39411fd4ff1116d" - "478987316a293fc2000000000000000000000000000000000819e3b10db116431ec6f7691539ce41" - "b95c593100000000dbe9962069e66142e22753344fda8a3e0b001cf7000000000000000000000000" - "000000008c54dda9ac3bb1b1d43e6505621b9a7f672d2fa501000000e276c5661a64192db44ce7af" - "5eb888e9eb73bb0400000000000000000000000000000002641e447514ca565fb9b68c08a5e4351e" - "9f3c39f201000000de745cb25851429b3bbfb50168dfd04edf2a3542000000000000000000000000" - "0000000218f93e742d08f0550b55726f2292362e70ccc56700000000a4c73cf5ffa4ffc8a4bab148" - "74afdf54e64be8160000000000000000000000000000000268baf76ab08940f6fc3bbdc7f6090f75" - "4f1b134803000000449a774929e86716ec852d59f3d17232ed3a6ad6000000000000000000000000" - "000000027dba1ee7e143fd52599364e13468f80f40b26f6603000000badfad0fe8fa8f3c1aad2a82" - "530b7447d93bf401000000000000000000000000000000028147507e1cd59ea1ae6da48b1eba6d16" - "dedea2030100000002a1f8e6f5657f3f9e3eb807cbad76451013edb8000000000000000000000000" - "00000002d9279fb2b8fcbac6abea74f7a6df7979f6989d2d000000006ff7add5df2c93e05459507b" - "5d8c6a0f465354d200000000000000000000ffff1785d3ffdbd9a617857ae8126b028c0e3e295354"), - [2] = ("4cc43c5103000000c2aac1d67a909b297c703915312e9c3c5a64c40b20ea99d5ab90135fa636af44" - "64d210a256be75e0509c4477d19ac64b2e69220d54270e46020000006a894e387625da376feecb80" - "ac245409c058cc271d9c2f67179bff0644399ae79c64ed0432d599eaa660ac824b7fae389861419c" - "12ea3b9501000000fb95e8332fdfff658483a2d039a7bf148e4c481e0bccc460e89f7abdb682380a" - "62eae374835b4a49a2b980b6aba92da6409969aa7a899f2d010000009bf5a5d06776e66a9d80ab13" - "2e1ac921eb04adbb229df32e561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" - "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ec5ffb112087b97cfcebbaeb0c565359" - "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9c4e1966800000000b3121cd5ef51e696c816290d" - "baee0e77264c82e1530ff5397c9125f59577d71c4b258a005116d11354edff62ceaa458fc75a91c4" - "25a5927300000000c4458d70911714f1819aa46fbe143934c915ae6dec0fb124f264af67eed7c9a8" - "c38b6b8ee2614344bea73223e59bf0193432e9fa2fea9bc10300000062fb81e733cff620ca7feefe" - "1933631e8e18f6d9fed62d2c6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" - "9985d62700000000e491cbbbf9443fd6a77eb3c5bf64b671d6098dbffeff9b8306c83bc026977911" - "4bdade862c224f6f36506ebd455e679cef369bb8bb0ec36f0000000064a2827b7cdd38d0314c178e" - "925b568ae566c4e9fefb24e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" - "02e9b69000000000eacce745ea213cb1a84035b632ef3be60755afa2fed87470e9da55709427c226" - "d324d9a086ed27184b443181a5edc511c1507a14d514573f03000000f6932f6932d1d5f5d0ce2cf6" - "bf7a70ba5111a162fe92ec1b11d9172cf84a03478b82cdd8883b0f3fd6ed84d6c959e553b887edcd" - "6297dfa700000000fd0d53bb6215de4bb6f6f3d031a790287e7be9c1feb836c0a25ea71f5daaed4d" - "99eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a4ae8cb60b0300000038d856a40c67c3d4afa9c864" - "9da90bd2ff4cf25600000000000000000000000000000001955e1a13d1111b067acbce3e3bcdf382" - "00154d12010000009edfa7a74c1c83c18e47935e8354846e346e386a000000000000000000000000" - "00000001ac26c7d41fd050bf8d85055bcfe3756c1e0f515601000000f57609453df7803357ae7998" - "9870ccec3d4f0ad9000000000000000000000000000000019f05a16768cb3bc873b04d937a6ed8f7" - "7c52a52d030000004e8e8bc17c01ac63eca0c1cfbb204132fb0813e4000000000000000000000000" - "00000000accae11f8045a80f855ebf3b772eb2b1d03bc90503000000eb760e3f004a2efc8ffc96b8" - "9b1bc8f415174e7700000000000000000000000000000000d149f074a378b881153ece68ade15cec" - "6f0e9e6903000000ec2e2924348352d715cf9d411ea012e5305a94b6000000000000000000000000" - "00000000ccd2f50c30706cae3fdcc2f0ee3d5e267666c05303000000ffa8e89871fb9510b900b206" - "1d0c334b816a2dd100000000000000000000000000000000095a3230fde69eec3af2e6d0bd68ab72" - "81ae55f0030000000aa20624fbab244735d67c61283031667b2274a1000000000000000000000000" - "0000000000459582f4ef43c780908872746e39ef10613fc90200000016a31dc2e46a234558817151" - "b38fc9c9093c8d7100000000000000000000000000000000ae17bb4515856092b4d9e89b676761b2" - "57d6249b020000007dc7f17f666969e45c3baf7a119a65ee0b08fa9e000000000000000000000000" - "00000000b314f695bd82e9ea8891ed0a3d1b91ca6e91b91501000000be5b534e0a6527f67485ab35" - "aca0c7ee4167338500000000000000000000000000000000aefd4503189f7630248e501c9052c22b" - "5d68265d010000009b7a559be3acf4fc36fa6b513cf09e8b99729462000000000000000000000000" - "00000000b49185ad9b7d0070a36dd51323b2c542b56e03e0010000002f70249eefc67bce716c856e" - "3973dc42a1003be9000000000000000000000000000000006176f78a19bb8df1804c122fce5078c1" - "e5fe7d360100000066a3ae3939762df33a2d55060c78d551cb7410fd000000000000000000000000" - "000000002c171ed15abbbe1cd911db7b56e8f3feeecc89f601000000d635edea8ffe423d01883918" - "039249f3984ab37e000000000000000000000000000000001fb7c8307f06b4b29088f20d9ac676d5" - "f90e54b501000000a779f37c30d2c5053c40ecae210aeb0934392a24000000000000000000000000" - "00000000df48f333ef467092818aa77d6732b678bcd7be0700000000e45aaf61814f703b40125e6b" - "af4648cbaa557b86000000000000000000000000000000005ddb05f2a84e27c18a06e2c9cb29efdf" - "50da49bf00000000d94beb259f9f0251becc987907879cca6857c7bb000000000000000000000000" - "000000009402a4c2167721673f2b02b3256ead1fa349e1cc00000000b879a45176740744fcb6a035" - "339d504c972bd80d000000000000000000000000000000009518862bc9a89192c1c8be55281a59d1" - "bae87d60000000005d31e5b2de252167c1c91b3a36ba0c700e538477000000000000000000000000" - "000000006ad0143a0554efb46b382ab0404cdf02ebfdcec30000000067a982be8a934f852cc3d4d8" - "2bc0ec7303579f8f00000000000000000000000000000000901f55f960c55c22f32099a8020bea2a" - "a2f56808092069affaa100fdfdd68d34be184524a6bdc8789c575178000000000000000000000000" - "00000000020ffdb0e612098610e52bb2a16a4008aefd545b020000007ced4f8b362956cd46646a0e" - "222160e5f749bb2900000000000000000000000000000000a19da86c64fefab2548759d313a5b92d" - "f05d7308020000009d82c856ba942455050f63f8282f34644466acf5000000000000000000000000" - "0000000069d9942f460bcea75481f25e307d0de99a6ce5d900000000a6a5ee19d6f63fe9cbdd01f7" - "246f13b2055624a200000000000000000000000000000000ffe9d6812231bb02f922259b173c333c" - "5b1aea3401000000c7c3523f76cf1ce34ca17a9a32f3f0f2187c4e48000000000000000000000000" - "00000002e6fbf952902383028e3b47f2111d891d17a4763102000000f9119c40b468b66331bca67a" - "034f43340d2c683c00000000000000000000ffffb24a5be9b10123e6e4f15ecd1dff045298cfee06" - "536c75bb01000000720da9e07ac998b5690807d52617369ee16d4ca500000000000000000000ffff" - "47d7b351a36b178aabc78a4a0d80684ee5dbf45bb0916e5d030000004a503a712350acbd48411f0d" - "c15d2f0f4952d345599706954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" - "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa700b120523bd98f29b098b43cd68be6e" - "3f81268193fd637e585287dc6ca972a2cfb18b2b3cae864b0200000091921681c2162b9bfa40546c" - "db544e44df587c2790d3119a051bb2ee8192ac0cfa3abc1ea0ab3e7d75a2f42b50c6a36340132378" - "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c03a56dfdcfc1155f236c8b9c79a620" - "5f660bbf024b03ff0a8e27c405e6424457393c6fdac12ebd01000000667224dae775e5ccd141aca2" - "ff0f57676754648102b61886b62f22ca33478e1f891715df7fc6a902edae579e2e10c7f7a22ba034" - "abf85f0c0100000008d33a2ea67776d7f88d69c8c7e3b2d3c951f054e93f8120abb42316c533d9c9" - "4d88189c471a1ff2f0ce3ff66e782110125ae2edc7a4c65601000000cd625009a40aeb62a42b6a62" - "548e3c38b96620022753c5fbfaf1809becd2506315a6da29b2e94d3ab51fe0e9af98b180a36035fb" - "daae7d6300000000c0982b283aa9986700b2a2b3ed257b8b042ff48f053ec8cac72105b327335a25" - "a364d1015ffac03089f45539e1b0178462156cd66855676c00000000017c9148da5892bb4951c3a7" - "ed55689d336bce7d3fd48469845f0c233dbdd2a97835df1f1782dee88487fd0db5971b46b7a350f9" - "cdb3455c00000000c66af76e80f062ea1a7e0b7be218d067532d1b0487b8c3b99f2b8a1a8982c42f" - "53700a3437c5156e072b2f2fb337c9cfe07c34ddc896c9a7000000000a5f6abd850b06e3d9662795" - "ce2cc1cee03202aba042aaa218dc091e9aa1477f6fdc9830d7fbc95829a8838314dff34d24c33221" - "98c39e7c00000000efc57ff447036b9551adcb22fd50793f791c3c7dadd1c86e759d0c90bc512e13" - "7dcef5e4a27985bd8d1e69c83dc21056b973972c7625ca4a00000000e682f80f94315c45ef817264" - "c89a736ed580d637b077ddad3108be69f9b97d05c917ad6b10e693bb6e26f2ba90c8e909e85e20e5" - "9c88b02a0300000004b0595daf37deb499996bfb667f072dec755d9cdc8a11f4409bcfb3c167090e" - "99d90a8543961b2ccd47724a3c460ba85183f4c5a7afe28302000000d05ff720b16c73761a3fcb67" - "5219061ab466c79489b2cc6a883c146972decb8b5adac8f5e6d66df46ea139107754dee62c36d2fc" - "e36f90d401000000fd41fe47684b370b6ec6584d64496089574568ead4d1ae91c819bb068196d599" - "efde3246e43f5e7945aaf95e2ffa3a11b9ef1b214d4647f5000000000f88e3759a08e7a56663861e" - "ea1bf42ccd1172f2ad063857ca82ac5180101be4f85cef468ea086ea9aaafdc388811ec787bc45db" - "0422ae3f03000000c43bd794c697895e5bfe47c6f53a54e01b211d89fecd94d0e02d2ec587fc3300" - "03781b0f294a2b73c4421398f4de67e9cee64b38bc51e540030000006c3d048a92d3adc69a84eb47" - "622400207708416afef0a086fbd7e2f7dea0077ae9c0c0d9c386e9c6e6a2cbfa10ee58bdc7518360" - "36674cde0200000054cfe8f42bf0e9381ba2c4396de60f032b5af34dfe959871c0d4c0d4eb720c4a" - "e3c9472e5f2da5d9c5cfd9f2343b21362c19a092b2cd3dbd01000000e958e48d2ab8b0313e7f8933" - "e315130fa9274c82feb83f6e70b1646d8026e9f1704f1b16286ba2dabc7ef0820c91ed33ef60a8b5" - "bcfe97e1000000007ad742d3d7320a4f880cf47f5dd0cf69cb7f840ffeb3fe7749509cb6752b2cee" - "30b7e7736a0afc9879ea40e69710fc9f6e8e99cd69121aec010000000fcc00ac2daa755e5292cd32" - "dc096cd5d830c5cffe91ee1cfcc2056cc1ff8e51bbce426cfa4b861cc78592be7b14e7ba9c15acb8" - "b83579b80300000072437f9b6245de39ec9e71ee4b951507be0a2b34000000000000000000000000" - "00000001d639272e4a46eadfbd2146bf8cfdb205b3980deb020000006c1de913df1424ce3ee1d76f" - "c1ea76e98c16fc7800000000000000000000000000000001e44ea74b4f2b83f9b3bee14d861a4c9e" - "cf844ef501000000cd743f59bd14c89b5cfd5ce6e82e7854157b2b70000000000000000000000000" - "0000000127e19f254ac9588319558041fc62ed561dce2f83020000003a3efc240b9977e166bee737" - "fe73670c436b644c000000000000000000000000000000015e0dfe491d1ba96742c7b5e02b227122" - "2af145480300000004265f6c72923e22594f3f79e208ed2e2e710771000000000000000000000000" - "0000000039dd8f88152a58454d9ca9d20f45dfa774993ade03000000e62112898dab2dade2ab2fc9" - "c56a7c86be73962200000000000000000000000000000000bdd06352cb2c354434819f4b248eb2b8" - "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f6042f061000000000000000000000000" - "000000008ae21e371051852c972ea7954079884a9f3c2c8803000000f51f44e644d7cf1d06b2b115" - "d882549e62042fba000000000000000000000000000000004fc812bd2f8a59d96d064126666befbb" - "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a0c1480000000000000000000000000" - "000000005588456e4ead7cbda620a3abae816e34e3ff1a5f03000000b4425486c619147eb0216050" - "ed7afd74105fe83600000000000000000000000000000000f493472201e48d163106cc397446a33f" - "f257b044030000006a4c619f9037d7a754655354c47cf0f551216770000000000000000000000000" - "0000000050b8d10ab700cc3a7cf51be0403b654bbc74179403000000438a72e12ae0436a2495a609" - "675344f7e226a5eb0000000000000000000000000000000061eda239d9d083c3bf085387046ef8a3" - "4153e174020000004d89c0bb5408c1b7d17fb084d9e1825fa613e1af000000000000000000000000" - "000000006e08cb887464b9344ec3127c750fabdd6c0fc09c02000000809829af4a9df58dbfef186d" - "416f3a1ef154d10f0000000000000000000000000000000087780281d47a32f2235376239daeaacb" - "74e7860402000000cd7db68b9ae586dacdb4070c50320427c4803d03000000000000000000000000" - "00000000d538d34574c038404923e75d0e09e2fca9a89f8701000000fcdf6d9be94030b34774d1d7" - "dddedd989972f62700000000000000000000000000000000848518c4e3f6cbf25e5e1b990fc46767" - "fd338f35010000006e8cc34573654ea6624f138ef9531cd9361802e4000000000000000000000000" - "00000000da40d88d40a6d75bc404156225b7eede2cb749e2010000000eb4f73e75039fcf251b32fc" - "79685b05dd3caa9b000000000000000000000000000000000d58fbcc58fc4c2fd0d44ff1e51c3515" - "6aae660b01000000fc1fb23d24438387def0f4c6544e4b275d4a7146000000000000000000000000" - "00000000b883efebc09dd9d61966b7ae7412041db7f0318a01000000061db3dd7fde25654a4059d5" - "65dbc8a91e00445700000000000000000000000000000000c1b5aad487c192f08bd7a09bdd214443" - "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e0e00b6000000000000000000000000" - "000000005e7fa0f02f2f3313d8469d09a92409c0b4d54acb00000000a417f3da01d99dae5f190096" - "cc582cabd534d15a00000000000000000000000000000000fdb3d117d76b0de5416f95e7bb75d72f" - "59747cf200000000ab2dadc5a39411fd4ff1116d478987316a293fc2000000000000000000000000" - "000000000819e3b10db116431ec6f7691539ce41b95c593100000000dbe9962069e66142e2275334" - "4fda8a3e0b001cf7000000000000000000000000000000008c54dda9ac3bb1b1d43e6505621b9a7f" - "fc2b445700000000496ad01bf007eacb0a28aec868282510b61b91ea000000000000000000000000" - "000000005b29a197b7b3cceaf5f1bb12c535256a0436242c03000000ee3fbc164632d4f28aa28c08" - "f80dd50c6705dfb400000000000000000000000000000000078a806d329c9b008bbfc9723107f3f5" - "9a1b163a030000000e2f4f911a0dd8c052ed6b13e2815a1a37322bdd000000000000000000000000" - "00000000bd99fcf72909ac9e7a55299e9bb4fd53fc1519de010000002545666937c22a3b6e9686dc" - "c405cbee504dc252000000000000000000000000000000006e4c699341b95f41d9c1e67743efb54e" - "d7ac5f9901000000822a272bec4501a1e27acfee7a8588ffd5286cae000000000000000000000000" - "0000000077a47579dda0b6ead1e1b34901eaedd54f1b134803000000449a774929e86716ec852d59" - "f3d17232ed3a6ad6000000000000000000000000000000027dba1ee7e143fd52599364e13468f80f" - "40b26f6603000000badfad0fe8fa8f3c1aad2a82530b7447d93bf401000000000000000000000000" - "000000028147507e1cd59ea1ae6da48b1eba6d16dedea2030100000002a1f8e6f5657f3f9e3eb807" - "cbad76451013edb800000000000000000000000000000002d9279fb2b8fcbac6abea74f7a6df7979" - "672d2fa501000000e276c5661a64192db44ce7af5eb888e9eb73bb04000000000000000000000000" - "00000002641e447514ca565fb9b68c08a5e4351e9f3c39f201000000de745cb25851429b3bbfb501" - "68dfd04edf2a35420000000000000000000000000000000218f93e742d08f0550b55726f2292362e" - "70ccc56700000000a4c73cf5ffa4ffc8a4bab14874afdf54e64be816000000000000000000000000" - "0000000268baf76ab08940f6fc3bbdc7f6090f75f6989d2d000000006ff7add5df2c93e05459507b" - "5d8c6a0f465354d200000000000000000000ffff1785d3ffdbd9a617857ae8126b028c0e3e295354"), + "5f660bbf024b03ff0a8e27c405e6424457393c6fd7ac5f996e8e99cd01000000644f0e8ab3121cd5" + "ef51e696c816290dba040e7726d082e1530ff5397c9125f59577d71c4b258a005116d11354edff62" + "ceaa458fc75a91c440e55b8b01000000c0cfb2b4386bec092fa5757ecde9348bda4c2ebd4f78a6aa" + "667224dae775e5ccd141aca2ff0f576767d3648102b61886b62f22ca33478e1fabf85f0c01000000" + "08d33a2ea67776d7f88d69c8c7e3b2d3c954f054e93f8120abb42316c533d9c94d88189c471a1ff2" + "f0ce3ff66e782110125ae2ed74993adeb4d9e89b010000006855676c277cf1bd017c9148da5892bb" + "4945c3a7ed55689d3391ce7d3fd48469845f0c233dbdd2a97835df1f1782dee88487fd0db5971b46" + "ae6da48b00000000bcfe97e1761e12457ad742d3d7320a4f8815f47f5dd0cf69cb22840f09b3fe77" + "49509cb6752b2cee30b7e7736a0afc9879ea40e69710fc9f2c19a0920000000092defa453a3efc24" + "0b9977e166bee737fe1c670c439a644c323b59b4cd20eb7dd3d38785c88ffad45e0dfe491d1ba967" + "42c7b5e02b2271220408423e00000000886dc91e2e5b0f0b65843fc961f7ad18014c3c67d9714f19" + "f1e41c073164d93b1171719c7f81773302d007c983566139c695e0f4b661ee6bc896c9a703000000" + "0a5f6abd850b06e3d9662795ce2cc1cee00802abfec2aaa218dc091e9aa1477f6fdc9830d7fbc958" + "29a8838314dff34d24c332219a1b163a3bbfb50103000000df6b3542f4bb5f574c5cf8107ba282f4" + "f9188219fef93e742d08f0550b55726f2292362e5d68265d9f98c82d9b7a559be3acf4fc36fa6b51" + "c8f1853b030000000e2b00b667b7b16dae02dfa0c26e7c3add113bd3febfa0f02f2f3313d8469d09" + "a92409c0b7f0318a575a4f8e061db3dd7fde25654a4059d5acdca10f01000000a36b178aabc78a4a" + "0d80684ee5dbf45bba3010fbfeb3cc24904f288262e6ea77a22fa5f863eaeefa701d120523bd98f2" + "9b098b43cd68be6e37c27c15000000007e5c53e755c90fa09e9653ddcb1b14d2757f8a13feac3c17" + "34b49e955cbcf46d256a1818053da43ec5085d1df74d1e287271092897e26251b442548601000000" + "b0216050ed7afd741024e8365ea1aa11f92797c0feac468e9de5a9caf493472201e48d163106cc39" + "7446a33fdc335c8b152c507a0a3c8e7c449a774903000000ec852d59f3d17232edd86ad6c3103a68" + "844c9aef00000000000000000000000000000001599364e13468f80fd514573fb572671cf6932f69" + "d9e1825f03000000284a024b7f9e85ff73e050a2cd89fd276e0acb88000000000000000000000000" + "00000001129cdc690fcc00ac2daa755e5292cd32dc096cd572437f9b02000000ec9e71ee4b951507" + "beb42b3473cef00e896b5f2400000000000000000000000000000001bd2146bf8cfdb205f90e54b5" + "8a6ee136a779f37c87bc45db0100000036bd39a44e8e8bc17c01ac63eca0c1cfbb4f413200000000" + "000000000000000000000001eca6d1adaccae11f8045a80f855ebf3b772eb2b103e0b1b101000000" + "90a2312e17f1a35900459582f4ef43c7807b887200000000000000000000000000000001e94030b3" + "4774d1d7dddedd9899f0f627be16965a050424a203000000a029c896b4132bd895072cfeffe9d681" + "2232bb0200000000000000000000000000000000eb760e3f004a2efc8ffc96b89b1bc8f415bd4e77" + "d611d7b103000000f9f23b5f1570a4648a0ff80dd9a37a82e10c20aa000000000000000000000000" + "00000000de6f36d664873c5be82c5361358730bcde43782df264af6703000000c38b6b8ee2614344" + "bea73223e59bf019345ae9fa000000000000000000000000000000009d80ab132e1ac921eb76adbb" + "229df32e561fa80ac7a4c65603000000cd625009a40aeb62a42b6a62548e3c38b96a200200000000" + "000000000000000000000000b2e94d3ab51fe0e9af98b180a36035fb6297dfa749ba9be302000000" + "0c67c3d4afa9c8649da90bd2fff2f2568108870b00000000000000000000000000000000d1111b06" + "7acbce3e3bcdf3824f1b134847ff26ba8704133102000000d9b4e3ce848518c4e3f6cbf25e5e1b99" + "0f13676700000000000000000000000000000000690807d52617369ee1af4ca5a6a95581af5fd7ce" + "b7a350f902000000fa7db4532545666937c22a3b6e9686dcc43ccbee000000000000000000000000" + "000000006ba04f146e4c699341b95f41d9c1e67743efb54e0e09e2fc01000000cc807cdce682f80f" + "94315c45ef817264c83c736e00000000000000000000000000000000c917ad6b10e693bb6e26f2ba" + "90c8e909e85e20e5182c028701000000ec4501a1e27acfee7a8588ffd5a06cae4228e59500000000" + "000000000000000000000000dda0b6ead1e1b34901eaedd5bcd7be07d78e62223cf09e8b01000000" + "e79c10acfce165e332a62384ec04e5bab46785ad00000000000000000000000000000000f86c260a" + "9edfa7a74c1c83c18e47935e8354846e4fc812bd010000006d064126666befbb98c39e7cc282208f" + "ef4a7ff400000000000000000000000000000000add1c86e759d0c90bc512e137dcef5e4a27985bd" + "9427c2260100000086ed27184b443181a5edc511c1507a141e4a5156000000000000000000000000" + "000000009870ccec3def0ad92749e016663fe6ee0228c1da0d58fbcc01000000d0d44ff1e51c3515" + "7666c05348e6f507ff72e89800000000000000000000000000000000cdf64b0f9a60e0e289f08db3" + "e4bafc4e095a32302b092583010000009f9f0251becc987907879cca68fec7bbbb4d8edf00000000" + "000000000000000000000000167721673f2b02b3256ead1f2fea9bc12f0cfca1078a806d00000000" + "8bbfc9723107f3f5b2cd3dbddc74e26de956e48d0000000000000000000000000000000088f83f6e" + "70b1646d8026e9f1704f1b16286ba2da0a6527f600000000aca0c7ee4197338581cafd63e66e3a23" + "d6572578000000000000000000000000000000009052c22b9f3c39f24b0572b1de745cb25851429b" + "1539ce410000000018238487a417f3da01d99dae5f190096cc292cab000000000000000000000000" + "00000000d8fbe9a4fdb3d117d76b0de5416f95e7bb75d72fb60291ea00000000def85b75827b26e8" + "a0bef8675b29a197b71bccea000000000000000000000000000000004a503a712350acbd48411f0d" + "c15d2f0f49dad3452931f2d30300000050b8d10ab700cc3a7cf51be0403b654ba242680800000000" + "000000000000000000000000a6bdc8789cf851782d895bcc8da98489c55b8c1237686b5e03000000" + "6215de4bb6f6f3d031a790287e45e9c18b7136c000000000000000000000000000000000ec7d3abc" + "4ccf30d3aaaf02a4f05d7308b67f91bfd8a4c5cf01000000fcc2056cc1ff8e51bbce426cfa4b861c" + "c73992be000000000000000000000000000000000aa20624fbab244735d67c61283031667b2d74a1" + "8c54dda900000000d43e6505621b9a7f0422ae3fc8979ee0c400d794000000000000000000000000" + "00000000414d94d0e02d2ec587fc330003781b0f294a2b738d1e69c801000000b973972c17a47631" + "c169f11ff9119c40b47cb66300000000000000000000000000000002ea4a849f060ddf57b24a5be9" + "b10123e6e4f15ecdc67b2e48000000001785d3ffdbd9a617857ae8126b028c0e3e4b535400000000" + "000000000000000000000002a84035b632ef3be6070dafa202187470e9da557036506ebd00000000" + "ef369bb8ebfdcec3f8c8fa6867a982be8a534f8500000000000000000000ffffe8d07c84965a316a" + "f2abb982b001ec16901f55f960c55c229c88b02a0200000004b0595daf37deb499996bfb667f072d" + "ec2c5d9c00000000000000000000ffff99d90a8543961b2ccd47724a3c460ba85183f4c5daae7d63"), }; const int TEST_DATA_I = GPOINTER_TO_INT(test_data); const int addr_family = (TEST_DATA_I == 0 ? AF_INET : AF_INET6); diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 148ed792..bd8fdc27 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -27,7 +27,7 @@ _wait_for_ipv4_addr_device_route(NMPlatform *platform, /* Wait that the addresses gets a device-route. After adding a address, * the device route is not added immediately. It takes a moment... */ - addr = nm_utils_ip4_address_clear_host_address(addr, plen); + addr = nm_ip4_addr_clear_host_address(addr, plen); NMTST_WAIT_ASSERT(400, { NMDedupMultiIter iter; NMPLookup lookup; @@ -41,7 +41,7 @@ _wait_for_ipv4_addr_device_route(NMPlatform *platform, &o) { const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(o); - if (r->plen == plen && addr == nm_utils_ip4_address_clear_host_address(r->network, plen) + if (r->plen == plen && addr == nm_ip4_addr_clear_host_address(r->network, plen) && r->metric == 0 && r->scope_inv == nm_platform_route_scope_inv(RT_SCOPE_LINK) && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) return; @@ -333,30 +333,33 @@ test_ip4_route(void) /* Test route listing */ routes = nmtstp_ip4_route_get_all(NM_PLATFORM_GET, ifindex); memset(rts, 0, sizeof(rts)); - rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[0].network = gateway; - rts[0].plen = 32; - rts[0].ifindex = ifindex; - rts[0].gateway = INADDR_ANY; - rts[0].metric = metric; - rts[0].mss = mss; - rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK); - rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[1].network = network; - rts[1].plen = plen; - rts[1].ifindex = ifindex; - rts[1].gateway = gateway; - rts[1].metric = metric; - rts[1].mss = mss; - rts[1].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); - rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); - rts[2].network = 0; - rts[2].plen = 0; - rts[2].ifindex = ifindex; - rts[2].gateway = gateway; - rts[2].metric = metric; - rts[2].mss = mss; - rts[2].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); + rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); + rts[0].network = gateway; + rts[0].plen = 32; + rts[0].ifindex = ifindex; + rts[0].gateway = INADDR_ANY; + rts[0].metric = metric; + rts[0].mss = mss; + rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK); + rts[0].n_nexthops = 1; + rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); + rts[1].network = network; + rts[1].plen = plen; + rts[1].ifindex = ifindex; + rts[1].gateway = gateway; + rts[1].metric = metric; + rts[1].mss = mss; + rts[1].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); + rts[1].n_nexthops = 1; + rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); + rts[2].network = 0; + rts[2].plen = 0; + rts[2].ifindex = ifindex; + rts[2].gateway = gateway; + rts[2].metric = metric; + rts[2].mss = mss; + rts[2].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE); + rts[2].n_nexthops = 1; g_assert_cmpint(routes->len, ==, 3); nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata, rts, @@ -635,21 +638,22 @@ test_ip4_route_options(gconstpointer test_data) switch (TEST_IDX) { case 1: rts_add[rts_n++] = ((NMPlatformIP4Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = nmtst_inet4_from_string("172.16.1.0"), - .plen = 24, - .metric = 20, - .tos = 0x28, - .window = 10000, - .cwnd = 16, - .initcwnd = 30, - .initrwnd = 50, - .mtu = 1350, - .lock_cwnd = TRUE, - .mss = 1300, - .quickack = TRUE, - .rto_min = 1000, + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string("172.16.1.0"), + .plen = 24, + .metric = 20, + .tos = 0x28, + .window = 10000, + .cwnd = 16, + .initcwnd = 30, + .initrwnd = 50, + .mtu = 1350, + .lock_cwnd = TRUE, + .mss = 1300, + .quickack = TRUE, + .rto_min = 1000, + .n_nexthops = 1, }); break; case 2: @@ -663,12 +667,13 @@ test_ip4_route_options(gconstpointer test_data) .n_ifa_flags = 0, }); rts_add[rts_n++] = ((NMPlatformIP4Route){ - .ifindex = IFINDEX, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = nmtst_inet4_from_string("172.17.1.0"), - .gateway = nmtst_inet4_from_string("172.16.1.1"), - .plen = 24, - .metric = 20, + .ifindex = IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = nmtst_inet4_from_string("172.17.1.0"), + .gateway = nmtst_inet4_from_string("172.16.1.1"), + .plen = 24, + .metric = 20, + .n_nexthops = 1, }); rts_add[rts_n++] = ((NMPlatformIP4Route){ .ifindex = IFINDEX, @@ -678,6 +683,7 @@ test_ip4_route_options(gconstpointer test_data) .r_rtm_flags = RTNH_F_ONLINK, .plen = 24, .metric = 20, + .n_nexthops = 1, }); break; default: @@ -691,24 +697,23 @@ test_ip4_route_options(gconstpointer test_data) const NMPlatformIP4Address *a = &addr[i]; g_assert(a->ifindex == IFINDEX); - g_assert(nm_platform_ip4_address_add( - NM_PLATFORM_GET, - a->ifindex, - a->address, - a->plen, - a->peer_address, - nm_platform_ip4_broadcast_address_create(a->address, a->plen), - a->lifetime, - a->preferred, - a->n_ifa_flags, - a->label)); + g_assert(nm_platform_ip4_address_add(NM_PLATFORM_GET, + a->ifindex, + a->address, + a->plen, + a->peer_address, + nm_ip4_addr_get_broadcast_address(a->address, a->plen), + a->lifetime, + a->preferred, + a->n_ifa_flags, + a->label)); if (a->peer_address == a->address) _wait_for_ipv4_addr_device_route(NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen); } for (i = 0; i < rts_n; i++) g_assert(NMTST_NM_ERR_SUCCESS( - nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]))); + nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i], NULL))); for (i = 0; i < rts_n; i++) { rts_cmp[i] = rts_add[i]; @@ -747,7 +752,7 @@ test_ip6_route_get(void) nmtstp_wait_for_signal(NM_PLATFORM_GET, 10); if (nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, - nmtst_inet6_from_string("fd01:abcd::"), + nmtst_inet6_from_string_p("fd01:abcd::"), 64, NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, NULL, @@ -755,7 +760,7 @@ test_ip6_route_get(void) break; }); - a = nmtst_inet6_from_string("fd01:abcd::42"); + a = nmtst_inet6_from_string_p("fd01:abcd::42"); result = nm_platform_ip_route_get(NM_PLATFORM_GET, AF_INET6, a, @@ -797,7 +802,7 @@ test_ip6_route_options(gconstpointer test_data) rts_add[rts_n++] = ((NMPlatformIP6Route){ .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = *nmtst_inet6_from_string("2001:db8:a:b:0:0:0:0"), + .network = nmtst_inet6_from_string("2001:db8:a:b:0:0:0:0"), .plen = 64, .gateway = in6addr_any, .metric = 1024, @@ -812,7 +817,7 @@ test_ip6_route_options(gconstpointer test_data) case 2: addr[addr_n++] = ((NMPlatformIP6Address){ .ifindex = IFINDEX, - .address = *nmtst_inet6_from_string("2000::2"), + .address = nmtst_inet6_from_string("2000::2"), .plen = 128, .peer_address = in6addr_any, .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, @@ -822,17 +827,17 @@ test_ip6_route_options(gconstpointer test_data) rts_add[rts_n++] = ((NMPlatformIP6Route){ .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .network = *nmtst_inet6_from_string("1010::1"), + .network = nmtst_inet6_from_string("1010::1"), .plen = 128, .gateway = in6addr_any, .metric = 256, - .pref_src = *nmtst_inet6_from_string("2000::2"), + .pref_src = nmtst_inet6_from_string("2000::2"), }); break; case 3: addr[addr_n++] = ((NMPlatformIP6Address){ .ifindex = IFINDEX, - .address = *nmtst_inet6_from_string("2001:db8:8086::5"), + .address = nmtst_inet6_from_string("2001:db8:8086::5"), .plen = 128, .peer_address = in6addr_any, .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, @@ -842,7 +847,7 @@ test_ip6_route_options(gconstpointer test_data) rts_add[rts_n++] = ((NMPlatformIP6Route){ .ifindex = IFINDEX, .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), - .network = *nmtst_inet6_from_string("2001:db8:8086::"), + .network = nmtst_inet6_from_string("2001:db8:8086::"), .plen = 110, .metric = 10021, .mss = 0, @@ -850,9 +855,9 @@ test_ip6_route_options(gconstpointer test_data) rts_add[rts_n++] = ((NMPlatformIP6Route){ .ifindex = IFINDEX, .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), - .network = *nmtst_inet6_from_string("2001:db8:abad:c0de::"), + .network = nmtst_inet6_from_string("2001:db8:abad:c0de::"), .plen = 64, - .gateway = *nmtst_inet6_from_string("2001:db8:8086::1"), + .gateway = nmtst_inet6_from_string("2001:db8:8086::1"), .metric = 21, .mss = 0, }); @@ -918,7 +923,7 @@ test_ip(gconstpointer test_data) const NMPlatformLink *l; char ifname[IFNAMSIZ]; char ifname2[IFNAMSIZ]; - char s1[NM_UTILS_INET_ADDRSTRLEN]; + char s1[NM_INET_ADDRSTRLEN]; NMPlatform *platform = NM_PLATFORM_GET; const int EX_ = -1; struct { @@ -983,8 +988,8 @@ again_find_idx: order_idx[order_len++] = idx; r->ifindex = iface_data[idx].ifindex; - g_assert( - NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r))); + g_assert(NMTST_NM_ERR_SUCCESS( + nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r, NULL))); } else { i = nmtst_get_rand_uint32() % order_len; idx = order_idx[i]; @@ -1171,7 +1176,7 @@ _rule_check_kernel_support(NMPlatform *platform, int attribute) .addr_family = AF_INET, .priority = PROBE_PRORITY, .uid_range = - { + { .start = 0, .end = 0, }, @@ -1278,7 +1283,7 @@ _rule_create_random(NMPlatform *platform) guint32 p; int addr_size; guint i; - char saddr[NM_UTILS_INET_ADDRSTRLEN]; + char saddr[NM_INET_ADDRSTRLEN]; static struct { guint32 uid; guint32 euid; @@ -1331,7 +1336,7 @@ _rule_create_random(NMPlatform *platform) p_addr->addr4 = nmtst_inet4_from_string(nm_sprintf_buf(saddr, "192.192.5.%u", (~p) % 256u)); else - p_addr->addr6 = *nmtst_inet6_from_string( + p_addr->addr6 = nmtst_inet6_from_string( nm_sprintf_buf(saddr, "1:2:3:4::f:%02x", (~p) % 256u)); } else if ((p % 3u) == 1) nmtst_rand_buf(NULL, p_addr, addr_size); @@ -1931,7 +1936,7 @@ test_blackhole(gconstpointer test_data) nm_platform_ip_route_normalize(addr_family, &rr.rx); if (IS_IPv4) - r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4); + r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4, NULL); else r = nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r6); @@ -2155,6 +2160,229 @@ test_mptcp(gconstpointer test_data) /*****************************************************************************/ +static void +_ensure_onlink_routes(void) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(NMTSTP_ENV1_DEVICE_NAME) && NMTSTP_ENV1_DEVICE_NAME[i]; i++) { + nmtstp_run_command("ip route append 7.7.7.0/24 dev %s%s", + NMTSTP_ENV1_DEVICE_NAME[i], + nmtst_is_debug() ? "" : " &>/dev/null"); + nmtstp_run_command("ip route append 7:7:7::/64 dev %s%s", + NMTSTP_ENV1_DEVICE_NAME[i], + nmtst_is_debug() ? "" : " &>/dev/null"); + } +} + +static void +test_cache_consistency_routes(gconstpointer test_data) +{ + const int TEST_IDX = GPOINTER_TO_INT(test_data); + NMPlatform *platform = NM_PLATFORM_GET; + gboolean is_test_quick = nmtst_test_quick(); + const int N_RUN = is_test_quick ? 50 : 500; + int i_run; + gs_unref_ptrarray GPtrArray *keeper = g_ptr_array_new_with_free_func(g_free); + + _ensure_onlink_routes(); + + for (i_run = 0; i_run < N_RUN; i_run++) { + const char *extra_options[100]; + gsize n_extra_options = 0; + gs_free char *extra_options_str = NULL; + int i_if; + int ifindex; + const char *ifname; + int IS_IPv4; + const char *op; + const char *prefix; + const char *s; + const char *route_type; + int i; + int n; + char addr_family_char[2] = {'6', '4'}; + + g_ptr_array_set_size(keeper, 0); + + switch (TEST_IDX) { + case 1: + IS_IPv4 = TRUE; + break; + case 2: + IS_IPv4 = FALSE; + break; + default: + IS_IPv4 = nmtst_get_rand_bool(); + break; + } + + i_if = nmtst_get_rand_uint32() % 2; + op = nmtst_rand_select_str("flush", "add", "change", "append", "prepend", "replace"); + + ifindex = NMTSTP_ENV1_IFINDEXES[i_if]; + ifname = NMTSTP_ENV1_DEVICE_NAME[i_if]; + + g_assert_cmpint(ifindex, ==, nm_platform_link_get_ifindex(platform, ifname)); + + if (nm_streq(op, "flush")) { + if (!nmtst_get_rand_one_case_in(10)) { + /* flush more seldom. */ + continue; + } + nmtstp_run_command("ip -%c route flush dev %s" + " table %s" /* table */ + "%s" /* redirect */ + "", + addr_family_char[IS_IPv4], + ifname, + nmtst_rand_select_str("main", "10222", "10223", "all"), + nmtst_is_debug() ? "" : " &>/dev/null"); + _ensure_onlink_routes(); + goto done; + } + + route_type = nmtst_get_rand_one_case_in(4) + ? nmtst_rand_select_str("unicast", "blackhole", "local", "broadcast") + : NULL; + + if (NM_IN_STRSET(route_type, "blackhole")) { + ifindex = 0; + ifname = NULL; + } + + if (IS_IPv4) { + prefix = nmtst_rand_select_str("192.168.4.0/24", + "192.168.5.0/24", + "192.168.5.5/32", + "default"); + } else { + prefix = + nmtst_rand_select_str("a:b:c:d::/64", "a:b:c:e::/64", "a:b:c:f::/64", "default"); + } + + s = nmtst_rand_select_str(NULL, "kernel", "bird"); + if (s) { + if (nmtst_get_rand_bool()) { + s = nm_streq(s, "kernel") ? nmtst_rand_select_str("boot", "static", "ra") + : nmtst_rand_select_str("zebra", "bird"); + } + extra_options[n_extra_options++] = "proto"; + extra_options[n_extra_options++] = s; + } + + s = nmtst_rand_select_str(NULL, "10", "20"); + if (s) { + extra_options[n_extra_options++] = "metric"; + extra_options[n_extra_options++] = s; + } + + s = nmtst_rand_select_str(NULL, "10222", "10223"); + if (s) { + extra_options[n_extra_options++] = "table"; + extra_options[n_extra_options++] = s; + } + + if (!IS_IPv4 && NM_IN_STRSET(op, "add", "change", "append", "prepend", "replace")) { + /* kernel has a bug with append/prepend of IPv6 routes with next-hops. + * This leads to wrong notification messages, wrong merging of multi-hop + * routes and cache inconsistency in NMPlatform. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=2161994 + * + * For now, disable the test case to make the unit test not fail. + * + * While being a kernel bug, it leads to cache inconsistency in NMPlatform, + * which is a problem for NetworkManager. I don't see how we can detect + * this problem to trigger a refresh. */ + } else if (ifname && nmtst_get_rand_one_case_in(3)) { + n = (nmtst_get_rand_uint32() % 4) + 1; + for (i = 0; i < n; i++) { + extra_options[n_extra_options++] = "nexthop"; + extra_options[n_extra_options++] = "via"; + if (IS_IPv4) { + extra_options[n_extra_options++] = + nmtst_keeper_printf(&keeper, "7.7.7.%d", i + 1); + } else { + extra_options[n_extra_options++] = + nmtst_keeper_printf(&keeper, "7:7:7:7::%d", i + 1); + } + extra_options[n_extra_options++] = "dev"; + extra_options[n_extra_options++] = NMTSTP_ENV1_DEVICE_NAME[nmtst_get_rand_bool()]; + if (IS_IPv4 && i == 0) { + /* For IPv4, there is a problem if we configure a route with + * only one next-hop and a weight. In that case, kernel allows + * to add duplicates (that only differ by weight), but on netlink + * the weight is not exposed, so the routes look identical and + * are deduplicated by the hash. + * See https://bugzilla.redhat.com/show_bug.cgi?id=2162315 + * + * This needs a kernel fix. Workaround that issue here, otherwise the test + * will randomly fail. */ + } else if (nmtst_get_rand_one_case_in(3)) { + extra_options[n_extra_options++] = "weight"; + extra_options[n_extra_options++] = "5"; + } + } + + ifname = NULL; + ifindex = 0; + } + + g_assert_cmpint(n_extra_options, <, G_N_ELEMENTS(extra_options)); + extra_options[n_extra_options] = NULL; + + if (nmtst_is_debug()) + nmtstp_run_command("ip -%c -d route show table all", addr_family_char[IS_IPv4]); + + /* We ignore errors. The reason is that operations like "change" might fail if + * the route doesn't exist. That's fine for our test. We just do randomly things + * and some of them will stick. */ + nmtstp_run_command( + "ip -%c route " + "%s" /* op */ + "%s%s" /* route_type */ + " %s" /* prefix */ + "%s%s" /* ifname */ + "%s%s" /* extra_options */ + "%s" /* redirect */ + "", + addr_family_char[IS_IPv4], + op, + NM_PRINT_FMT_QUOTED2(route_type, " ", route_type, ""), + prefix, + NM_PRINT_FMT_QUOTED2(ifname, " dev ", ifname, ""), + NM_PRINT_FMT_QUOTED2(extra_options[0], + " ", + (extra_options_str = g_strjoinv(" ", (char **) extra_options)), + ""), + nmtst_is_debug() ? "" : " &>/dev/null"); + + if (nmtst_is_debug()) + nmtstp_run_command("ip -%c -d route show table all", addr_family_char[IS_IPv4]); +done: + nm_platform_process_events(platform); + + if (!is_test_quick || (i_run + 1 == N_RUN) || nmtst_get_rand_one_case_in(5)) { + nmtstp_check_platform( + platform, + nmtst_get_rand_one_case_in(5) + ? 0u + : nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))); + } + } + + if (is_test_quick) { + gs_free char *msg = NULL; + + msg = g_strdup_printf("Ran a quick version of test %s (try NMTST_DEBUG=slow)", + nmtst_test_get_path()); + g_test_skip(msg); + } +} + +/*****************************************************************************/ + NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void @@ -2166,9 +2394,11 @@ _nmtstp_init_tests(int *argc, char ***argv) void _nmtstp_setup_tests(void) { -#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, TRUE) +#define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, 1, TRUE) #define add_test_func_data(testpath, test_func, arg) \ - nmtstp_env1_add_test_func_data(testpath, test_func, arg, TRUE) + nmtstp_env1_add_test_func_data(testpath, test_func, arg, 1, TRUE) +#define add_test_func_data_with_if2(testpath, test_func, arg) \ + nmtstp_env1_add_test_func_data(testpath, test_func, arg, 2, TRUE) add_test_func("/route/ip4", test_ip4_route); add_test_func("/route/ip6", test_ip6_route); @@ -2201,4 +2431,15 @@ _nmtstp_setup_tests(void) add_test_func_data("/route/mptcp/1", test_mptcp, GINT_TO_POINTER(1)); add_test_func_data("/route/mptcp/2", test_mptcp, GINT_TO_POINTER(2)); } + if (nmtstp_is_root_test()) { + add_test_func_data_with_if2("/route/test_cache_consistency_routes/1", + test_cache_consistency_routes, + GINT_TO_POINTER(1)); + add_test_func_data_with_if2("/route/test_cache_consistency_routes/2", + test_cache_consistency_routes, + GINT_TO_POINTER(2)); + add_test_func_data_with_if2("/route/test_cache_consistency_routes/3", + test_cache_consistency_routes, + GINT_TO_POINTER(3)); + } } diff --git a/src/core/platform/tests/test-tc.c b/src/core/platform/tests/test-tc.c index 6a2019c8..832fbea6 100644 --- a/src/core/platform/tests/test-tc.c +++ b/src/core/platform/tests/test-tc.c @@ -214,8 +214,8 @@ _nmtstp_init_tests(int *argc, char ***argv) void _nmtstp_setup_tests(void) { - nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, TRUE); - nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/1", test_qdisc1, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/fq_codel", test_qdisc_fq_codel, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/sfq", test_qdisc_sfq, 1, TRUE); + nmtstp_env1_add_test_func("/link/qdisc/tbf", test_qdisc_tbf, 1, TRUE); } diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index 003a9806..14cd5731 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -66,7 +66,8 @@ static NM_CACHED_QUARK_FCN("ppp-manager-secret-tries", ppp_manager_secret_tries_ /*****************************************************************************/ #define NM_TYPE_PPP_MANAGER (nm_ppp_manager_get_type()) -#define NM_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_MANAGER, NMPPPManager)) +#define NM_PPP_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_MANAGER, NMPPPManager)) #define NM_PPP_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_PPP_MANAGER, NMPPPManagerClass)) #define NM_IS_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_PPP_MANAGER)) @@ -582,7 +583,7 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *obj, if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &u32); + nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &u32, NULL); g_variant_iter_free(iter); } diff --git a/src/core/ppp/nm-ppp-mgr.c b/src/core/ppp/nm-ppp-mgr.c index 31c173a3..bebffaf3 100644 --- a/src/core/ppp/nm-ppp-mgr.c +++ b/src/core/ppp/nm-ppp-mgr.c @@ -68,7 +68,7 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_ppp_mgr_callback_type_to_string, #define SELF_TO_USERDATA(self) (&(self)->idle_start) #define SELF_FROM_USERDATA(user_data) \ - ((NMPppMgr *) (((const char *) (user_data)) - G_STRUCT_OFFSET(NMPppMgr, idle_start))) + NM_CAST_ALIGN(NMPppMgr, (((char *) (user_data)) - G_STRUCT_OFFSET(NMPppMgr, idle_start))) /*****************************************************************************/ diff --git a/src/core/settings/nm-agent-manager.c b/src/core/settings/nm-agent-manager.c index 295378bc..0a120649 100644 --- a/src/core/settings/nm-agent-manager.c +++ b/src/core/settings/nm-agent-manager.c @@ -1172,8 +1172,10 @@ _con_get_try_complete_early(Request *req) } /* Do we have everything we need? */ if (NM_FLAGS_HAS(req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM) - || ((nm_connection_need_secrets(tmp, NULL) == NULL) - && !NM_FLAGS_HAS(req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW))) { + || (NM_FLAGS_HAS(req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) + && !nm_connection_need_secrets_for_rerequest(tmp)) + || (!NM_FLAGS_HAS(req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) + && !nm_connection_need_secrets(tmp, NULL))) { _LOGD(NULL, "(" LOG_REQ_FMT ") system settings secrets sufficient", LOG_REQ_ARG(req)); /* Got everything, we're done */ diff --git a/src/core/settings/nm-agent-manager.h b/src/core/settings/nm-agent-manager.h index cae8e8e0..e5c6e31c 100644 --- a/src/core/settings/nm-agent-manager.h +++ b/src/core/settings/nm-agent-manager.h @@ -13,7 +13,7 @@ #define NM_TYPE_AGENT_MANAGER (nm_agent_manager_get_type()) #define NM_AGENT_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AGENT_MANAGER, NMAgentManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_AGENT_MANAGER, NMAgentManager)) #define NM_AGENT_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) #define NM_IS_AGENT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_AGENT_MANAGER)) diff --git a/src/core/settings/nm-secret-agent.h b/src/core/settings/nm-secret-agent.h index 14458b38..eb8dd382 100644 --- a/src/core/settings/nm-secret-agent.h +++ b/src/core/settings/nm-secret-agent.h @@ -12,7 +12,7 @@ #define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type()) #define NM_SECRET_AGENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) #define NM_SECRET_AGENT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) #define NM_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SECRET_AGENT)) diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h index 893b0d7b..47599c3d 100644 --- a/src/core/settings/nm-settings-connection.h +++ b/src/core/settings/nm-settings-connection.h @@ -122,7 +122,7 @@ typedef enum { #define NM_TYPE_SETTINGS_CONNECTION (nm_settings_connection_get_type()) #define NM_SETTINGS_CONNECTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnection)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnection)) #define NM_SETTINGS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionClass)) #define NM_IS_SETTINGS_CONNECTION(obj) \ diff --git a/src/core/settings/nm-settings-plugin.h b/src/core/settings/nm-settings-plugin.h index 198447c0..c9d1265f 100644 --- a/src/core/settings/nm-settings-plugin.h +++ b/src/core/settings/nm-settings-plugin.h @@ -26,7 +26,7 @@ typedef struct { #define NM_TYPE_SETTINGS_PLUGIN (nm_settings_plugin_get_type()) #define NM_SETTINGS_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPlugin)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPlugin)) #define NM_SETTINGS_PLUGIN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPluginClass)) #define NM_IS_SETTINGS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTINGS_PLUGIN)) diff --git a/src/core/settings/nm-settings-storage.h b/src/core/settings/nm-settings-storage.h index 198b0e8b..65750152 100644 --- a/src/core/settings/nm-settings-storage.h +++ b/src/core/settings/nm-settings-storage.h @@ -12,7 +12,7 @@ #define NM_TYPE_SETTINGS_STORAGE (nm_settings_storage_get_type()) #define NM_SETTINGS_STORAGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_STORAGE, NMSettingsStorage)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS_STORAGE, NMSettingsStorage)) #define NM_SETTINGS_STORAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTINGS_STORAGE, NMSettingsStorageClass)) #define NM_IS_SETTINGS_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTINGS_STORAGE)) diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index b7d846c6..9995b490 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -2009,6 +2009,7 @@ nm_settings_update_connection(NMSettings *self, const char *uuid; gboolean tombstone_in_memory = FALSE; gboolean tombstone_on_disk = FALSE; + NMSettingsConnectionIntFlags new_flags; g_return_val_if_fail(NM_IS_SETTINGS(self), FALSE); g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(sett_conn), FALSE); @@ -2228,13 +2229,16 @@ nm_settings_update_connection(NMSettings *self, } } + new_flags = nm_settings_connection_get_flags(sett_conn); + new_flags = NM_FLAGS_ASSIGN_MASK(new_flags, sett_mask, sett_flags); + if (!update_storage) { success = _add_connection_to_first_plugin(self, plugin_name, sett_conn_entry, connection, new_in_memory, - sett_flags, + new_flags, new_shadowed_storage_filename, new_shadowed_owned, &new_storage, @@ -2245,7 +2249,7 @@ nm_settings_update_connection(NMSettings *self, success = _update_connection_to_plugin(self, update_storage, connection, - sett_flags, + new_flags, update_reason, new_shadowed_storage_filename, new_shadowed_owned, @@ -3479,7 +3483,7 @@ _save_hostname_write_cb(GObject *source, GAsyncResult *result, gpointer user_dat nm_utils_user_data_unpack(user_data, &self, &context, &auth_subject, &hostname, &cancellable); - nm_hostname_manager_write_hostname_finish(NM_HOSTNAME_MANAGER(source), result, &error); + nm_hostname_manager_set_static_hostname_finish(NM_HOSTNAME_MANAGER(source), result, &error); nm_audit_log_control_op(NM_AUDIT_OP_HOSTNAME_SAVE, hostname ?: "", @@ -3544,7 +3548,7 @@ _save_hostname_pk_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointe (gpointer *) &priv->shutdown_cancellable); } - nm_hostname_manager_write_hostname( + nm_hostname_manager_set_static_hostname( priv->hostname_manager, hostname, priv->shutdown_cancellable, diff --git a/src/core/settings/nm-settings.h b/src/core/settings/nm-settings.h index 8747d1dc..aba3c565 100644 --- a/src/core/settings/nm-settings.h +++ b/src/core/settings/nm-settings.h @@ -15,7 +15,7 @@ #include "nm-settings-connection.h" #define NM_TYPE_SETTINGS (nm_settings_get_type()) -#define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS, NMSettings)) +#define NM_SETTINGS(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTINGS, NMSettings)) #define NM_SETTINGS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTINGS, NMSettingsClass)) #define NM_IS_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTINGS)) diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h index dc1a01c8..49e04291 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.h @@ -10,7 +10,7 @@ #define NMS_TYPE_IFCFG_RH_PLUGIN (nms_ifcfg_rh_plugin_get_type()) #define NMS_IFCFG_RH_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPlugin)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPlugin)) #define NMS_IFCFG_RH_PLUGIN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPluginClass)) #define NMS_IS_IFCFG_RH_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_IFCFG_RH_PLUGIN)) 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 4d8e7bd6..aa593331 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 @@ -739,7 +739,7 @@ read_full_ip4_address(shvarFile *ifcfg, int prefix = 0; gboolean has_key; guint32 a; - char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; + char inet_buf[NM_INET_ADDRSTRLEN]; g_return_val_if_fail(which >= -1, FALSE); g_return_val_if_fail(ifcfg != NULL, FALSE); @@ -761,7 +761,7 @@ read_full_ip4_address(shvarFile *ifcfg, if (!read_ip4_address(ifcfg, numbered_tag(tag, "GATEWAY", which), &has_key, &a, error)) return FALSE; if (has_key) - *out_gateway = nm_utils_inet4_ntop_dup(a); + *out_gateway = nm_inet4_ntop_dup(a); } /* Prefix */ @@ -782,16 +782,16 @@ read_full_ip4_address(shvarFile *ifcfg, if (!read_ip4_address(ifcfg, numbered_tag(tag, "NETMASK", which), &has_key, &a, error)) return FALSE; if (has_key) - prefix = _nm_utils_ip4_netmask_to_prefix(a); + prefix = nm_ip4_addr_netmask_to_prefix(a); else { if (base_addr) prefix = nm_ip_address_get_prefix(base_addr); else { /* Try to autodetermine the prefix for the address' class */ - prefix = _nm_utils_ip4_get_default_prefix(ipaddr); + prefix = nm_ip4_addr_get_default_prefix(ipaddr); PARSE_WARNING("missing %s, assuming %s/%d", prefix_tag, - _nm_utils_inet4_ntop(ipaddr, inet_buf), + nm_inet4_ntop(ipaddr, inet_buf), prefix); } } @@ -887,6 +887,7 @@ enum { PARSE_LINE_ATTR_ROUTE_ADVMSS, PARSE_LINE_ATTR_ROUTE_RTO_MIN, PARSE_LINE_ATTR_ROUTE_QUICKACK, + PARSE_LINE_ATTR_ROUTE_WEIGHT, /* iproute2 arguments that only matter when parsing the file. */ PARSE_LINE_ATTR_ROUTE_TO, @@ -966,6 +967,12 @@ parse_route_line(const char *line, .int_base_16 = TRUE, .ignore = PARSE_LINE_AF_FLAG_FOR_IPV6, }, + [PARSE_LINE_ATTR_ROUTE_WEIGHT] = + { + .key = NM_IP_ROUTE_ATTRIBUTE_WEIGHT, + .type = PARSE_LINE_TYPE_UINT32, + .disabled = PARSE_LINE_AF_FLAG_FOR_IPV6, + }, [PARSE_LINE_ATTR_ROUTE_SCOPE] = { .key = NM_IP_ROUTE_ATTRIBUTE_SCOPE, @@ -1282,7 +1289,7 @@ parse_line_type_addr_with_prefix: int prefix = -1; if (p_info->type == PARSE_LINE_TYPE_ADDR) { - if (!nm_utils_parse_inaddr_bin(addr_family, s, NULL, &p_data->v.addr.addr)) { + if (!nm_inet_parse_bin(addr_family, s, NULL, &p_data->v.addr.addr)) { if (p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_VIA] && nm_streq(s, "(null)")) { /* Due to a bug, would older versions of NM write "via (null)" @@ -1313,11 +1320,11 @@ parse_line_type_addr_with_prefix: if (p_info == &parse_infos[PARSE_LINE_ATTR_ROUTE_TO] && nm_streq(s, "default")) { memset(&p_data->v.addr.addr, 0, sizeof(p_data->v.addr.addr)); prefix = 0; - } else if (!nm_utils_parse_inaddr_prefix_bin(addr_family, - s, - NULL, - &p_data->v.addr.addr, - &prefix)) { + } else if (!nm_inet_parse_with_prefix_bin(addr_family, + s, + NULL, + &p_data->v.addr.addr, + &prefix)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -1468,7 +1475,7 @@ read_one_ip4_route(shvarFile *ifcfg, guint32 which, NMIPRoute **out_route, GErro const char *v; gs_free char *value = NULL; gint64 prefix, metric; - char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; + char inet_buf[NM_INET_ADDRSTRLEN]; g_return_val_if_fail(ifcfg != NULL, FALSE); g_return_val_if_fail(out_route && !*out_route, FALSE); @@ -1496,14 +1503,14 @@ read_one_ip4_route(shvarFile *ifcfg, guint32 which, NMIPRoute **out_route, GErro error)) return FALSE; if (has_key) { - prefix = _nm_utils_ip4_netmask_to_prefix(netmask); - if (netmask != _nm_utils_ip4_prefix_to_netmask(prefix)) { + prefix = nm_ip4_addr_netmask_to_prefix(netmask); + if (netmask != nm_ip4_addr_netmask_from_prefix(prefix)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, - _nm_utils_inet4_ntop(netmask, inet_buf)); + nm_inet4_ntop(netmask, inet_buf)); return FALSE; } } else { @@ -1667,7 +1674,7 @@ parse_full_ip6_address(shvarFile *ifcfg, nm_assert(out_address && !*out_address); nm_assert(!error || !*error); - if (!nm_utils_parse_inaddr_prefix_bin(AF_INET6, addr_str, NULL, &addr_bin, &prefix)) { + if (!nm_inet_parse_with_prefix_bin(AF_INET6, addr_str, NULL, &addr_bin, &prefix)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -1935,6 +1942,10 @@ make_ip4_setting(shvarFile *ifcfg, (guint) route_table, NM_SETTING_IP4_CONFIG_LINK_LOCAL, ipv4_link_local, + NM_SETTING_IP_CONFIG_AUTO_ROUTE_EXT_GW, + svGetValueTernary(ifcfg, "IPV4_AUTO_ROUTE_EXT_GW"), + NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE, + svGetValueTernary(ifcfg, "IPV4_REPLACE_LOCAL_RULE"), NULL); if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) @@ -2027,7 +2038,7 @@ make_ip4_setting(shvarFile *ifcfg, "because the connection has no static addresses", f); } else - gateway = nm_utils_inet4_ntop_dup(a); + gateway = nm_inet4_ntop_dup(a); } } } @@ -2047,7 +2058,9 @@ make_ip4_setting(shvarFile *ifcfg, * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) */ for (i = 1; i < 10000; i++) { - char tag[256]; + int af; + NMIPAddr ip; + char tag[256]; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2055,18 +2068,18 @@ make_ip4_setting(shvarFile *ifcfg, if (!v) break; - if (nm_utils_ipaddr_is_valid(AF_INET, v)) { - if (!nm_setting_ip_config_add_dns(s_ip4, v)) - PARSE_WARNING("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_is_valid(AF_INET6, v)) { - /* Ignore IPv6 addresses */ - } else { + if (!nm_utils_dnsname_parse(AF_UNSPEC, v, &af, &ip, NULL)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid DNS server address '%s'", v); return NULL; + } else if (af == AF_INET) { + if (!nm_setting_ip_config_add_dns(s_ip4, v)) + PARSE_WARNING("duplicate DNS server %s", tag); + } else { + /* Ignore IPv6 addresses */ } } @@ -2446,6 +2459,10 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea (guint) route_table, NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val, + NM_SETTING_IP_CONFIG_AUTO_ROUTE_EXT_GW, + svGetValueTernary(ifcfg, "IPV6_AUTO_ROUTE_EXT_GW"), + NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE, + svGetValueTernary(ifcfg, "IPV6_REPLACE_LOCAL_RULE"), NULL); /* Don't bother to read IP, DNS and routes when IPv6 is disabled */ @@ -2546,7 +2563,7 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea if ((ptr = strchr(v, '%')) != NULL) *ptr = '\0'; /* remove %interface prefix if present */ - if (!nm_utils_ipaddr_is_valid(AF_INET6, v)) { + if (!nm_inet_is_valid(AF_INET6, v)) { if (!is_disabled) { g_set_error(error, NM_SETTINGS_ERROR, @@ -2586,7 +2603,9 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) */ for (i = 1; i < 10000; i++) { - char tag[256]; + int af; + NMIPAddr ip; + char tag[256]; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2594,16 +2613,7 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea if (!v) break; - if (nm_utils_ipaddr_is_valid(AF_INET6, v)) { - if (is_disabled) { - PARSE_WARNING("ignore DNS server addresses with method disabled/ignore"); - break; - } - if (!nm_setting_ip_config_add_dns(s_ip6, v)) - PARSE_WARNING("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_is_valid(AF_INET, v)) { - /* Ignore IPv4 addresses */ - } else { + if (!nm_utils_dnsname_parse(AF_UNSPEC, v, &af, &ip, NULL)) { if (is_disabled) continue; g_set_error(error, @@ -2612,6 +2622,15 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea "Invalid DNS server address '%s'", v); return NULL; + } else if (af == AF_INET6) { + if (is_disabled) { + PARSE_WARNING("ignore DNS server addresses with method disabled/ignore"); + break; + } + if (!nm_setting_ip_config_add_dns(s_ip6, v)) + PARSE_WARNING("duplicate DNS server %s", tag); + } else { + /* Ignore IPv4 addresses */ } } @@ -6227,6 +6246,11 @@ make_vlan_setting(shvarFile *ifcfg, const char *file, GError **error) } g_object_set(s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL); + v = svGetValueStr(ifcfg, "VLAN_PROTOCOL", &value); + if (v) { + g_object_set(s_vlan, NM_SETTING_VLAN_PROTOCOL, v, NULL); + } + vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS; gvrp = svGetValueBoolean(ifcfg, "GVRP", -1); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h index 2ab6beb6..737c9614 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.h @@ -13,7 +13,7 @@ #define NMS_TYPE_IFCFG_RH_STORAGE (nms_ifcfg_rh_storage_get_type()) #define NMS_IFCFG_RH_STORAGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFCFG_RH_STORAGE, NMSIfcfgRHStorage)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFCFG_RH_STORAGE, NMSIfcfgRHStorage)) #define NMS_IFCFG_RH_STORAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_IFCFG_RH_STORAGE, NMSIfcfgRHStorageClass)) #define NMS_IS_IFCFG_RH_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_IFCFG_RH_STORAGE)) diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index e1ef8174..552310dd 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -957,10 +957,12 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("IEEE_8021X_SUBJECT_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IEEE_8021X_SYSTEM_CA_CERTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPADDR", NMS_IFCFG_KEY_TYPE_IS_NUMBERED), + _KEY_TYPE("IPV4_AUTO_ROUTE_EXT_GW", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_DHCP_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_DNS_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_FAILURE_FATAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_LINK_LOCAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("IPV4_REPLACE_LOCAL_RULE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_REQUIRED_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -971,6 +973,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("IPV6TUNNELIPV4", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_ADDR_GEN_MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_AUTOCONF", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("IPV6_AUTO_ROUTE_EXT_GW", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_DEFAULTDEV", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_DEFAULTGW", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_DEFROUTE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -984,6 +987,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("IPV6_PRIVACY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_PRIVACY_PREFER_PUBLIC_IP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_RA_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("IPV6_REPLACE_LOCAL_RULE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_REQUIRED_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_RES_OPTIONS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV6_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -1061,6 +1065,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("VLAN_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VLAN_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VLAN_INGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("VLAN_PROTOCOL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VRF", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VRF_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("WAIT_ACTIVATION_DELAY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -1080,12 +1085,12 @@ nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx) G_STATIC_ASSERT(G_STRUCT_OFFSET(NMSIfcfgKeyTypeInfo, key_name) == 0); - idx = nm_utils_array_find_binary_search(nms_ifcfg_well_known_keys, - sizeof(nms_ifcfg_well_known_keys[0]), - G_N_ELEMENTS(nms_ifcfg_well_known_keys), - &key, - nm_strcmp_p_with_data, - NULL); + idx = nm_array_find_bsearch(nms_ifcfg_well_known_keys, + G_N_ELEMENTS(nms_ifcfg_well_known_keys), + sizeof(nms_ifcfg_well_known_keys[0]), + &key, + nm_strcmp_p_with_data, + NULL); NM_SET_OUT(out_idx, idx); if (idx < 0) return NULL; diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index d1f8dbad..4fa9f18c 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[256]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[261]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index e8948c3d..41260020 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1453,6 +1453,7 @@ write_vlan_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired, svSetValueStr(ifcfg, "TYPE", TYPE_VLAN); svSetValueStr(ifcfg, "PHYSDEV", nm_setting_vlan_get_parent(s_vlan)); svSetValueInt64(ifcfg, "VLAN_ID", nm_setting_vlan_get_id(s_vlan)); + svSetValueStr(ifcfg, "VLAN_PROTOCOL", nm_setting_vlan_get_protocol(s_vlan)); vlan_flags = nm_setting_vlan_get_flags(s_vlan); svSetValueBoolean(ifcfg, "REORDER_HDR", NM_FLAGS_HAS(vlan_flags, NM_VLAN_FLAG_REORDER_HEADERS)); @@ -2359,13 +2360,14 @@ get_route_attributes_string(NMIPRoute *route, int family) /* we also have a corresponding attribute with the numeric value. The * lock setting is handled above. */ } - } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_SCOPE)) { + } else if (NM_IN_STRSET(names[i], NM_IP_ROUTE_ATTRIBUTE_SCOPE)) { g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_byte(attr)); } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { g_string_append_printf(str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte(attr)); } else if (NM_IN_STRSET(names[i], + NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, NM_IP_ROUTE_ATTRIBUTE_TABLE, - NM_IP_ROUTE_ATTRIBUTE_RTO_MIN)) { + NM_IP_ROUTE_ATTRIBUTE_WEIGHT)) { g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_uint32(attr)); } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_QUICKACK)) { g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_boolean(attr)); @@ -2416,8 +2418,8 @@ write_route_file_svformat(const char *filename, NMSettingIPConfig *s_ip4) svSetValueStr(routefile, addr_key, nm_ip_route_get_dest(route)); - netmask = _nm_utils_ip4_prefix_to_netmask(nm_ip_route_get_prefix(route)); - svSetValueStr(routefile, netmask_key, _nm_utils_inet4_ntop(netmask, buf)); + netmask = nm_ip4_addr_netmask_from_prefix(nm_ip_route_get_prefix(route)); + svSetValueStr(routefile, netmask_key, nm_inet4_ntop(netmask, buf)); svSetValueStr(routefile, gw_key, nm_ip_route_get_next_hop(route)); @@ -2826,9 +2828,7 @@ write_ip4_setting(NMConnection *connection, if (has_netmask) { char buf[INET_ADDRSTRLEN]; - svSetValueStr(ifcfg, - tag, - _nm_utils_inet4_ntop(_nm_utils_ip4_prefix_to_netmask(prefix), buf)); + svSetValueStr(ifcfg, tag, nm_inet4_ntop(nm_ip4_addr_netmask_from_prefix(prefix), buf)); } n++; @@ -2937,6 +2937,14 @@ write_ip4_setting(NMConnection *connection, } svSetValueStr(ifcfg, "DHCP_REJECT_SERVERS", str->str); } + + svSetValueTernary(ifcfg, + "IPV4_AUTO_ROUTE_EXT_GW", + nm_setting_ip_config_get_auto_route_ext_gw(s_ip4)); + + svSetValueTernary(ifcfg, + "IPV4_REPLACE_LOCAL_RULE", + nm_setting_ip_config_get_replace_local_rule(s_ip4)); } static void @@ -3197,6 +3205,14 @@ write_ip6_setting(NMConnection *connection, shvarFile *ifcfg, GString **out_rout write_res_options(ifcfg, s_ip6, "IPV6_RES_OPTIONS"); NM_SET_OUT(out_route6_content, write_route_file(s_ip6)); + + svSetValueTernary(ifcfg, + "IPV6_AUTO_ROUTE_EXT_GW", + nm_setting_ip_config_get_auto_route_ext_gw(s_ip6)); + + svSetValueTernary(ifcfg, + "IPV6_REPLACE_LOCAL_RULE", + nm_setting_ip_config_get_replace_local_rule(s_ip6)); } static void diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected index 6ad151aa..6373da90 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Vlan_test-vlan-interface.cexpected @@ -2,6 +2,7 @@ VLAN=yes TYPE=Vlan PHYSDEV=eth9 VLAN_ID=43 +VLAN_PROTOCOL=802.1ad REORDER_HDR=yes GVRP=yes VLAN_FLAGS=LOOSE_BINDING diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1 b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1 index ecb36c37..5e40362e 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1 +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1 @@ -1,4 +1,7 @@ DNS1="192.0.2.1" +DNS2="192.0.2.2#adfs.afddsaf" +DNS3="1::2" +DNS4="1::3#dfdf.er" IPADDR="102.0.2.2" GATEWAY="192.0.2.1" NETMASK="255.254.0.0" diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected index 87493ac2..d0eeeb99 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected @@ -1,4 +1,7 @@ DNS1=192.0.2.1 +DNS2=192.0.2.2#adfs.afddsaf +DNS3=1::2 +DNS4=1::3#dfdf.er IPADDR=102.0.2.2 GATEWAY=192.0.2.1 NETMASK=255.254.0.0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface index d8d9193f..38fe4069 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-interface @@ -5,6 +5,7 @@ PHYSDEV=eth9 VLAN_FLAGS=GVRP,LOOSE_BINDING VLAN_INGRESS_PRIORITY_MAP=0:1,2:5 VLAN_EGRESS_PRIORITY_MAP=12:3,14:7,3:1 +VLAN_PROTOCOL=802.1ad ONBOOT=yes BOOTPROTO=static IPADDR=192.168.43.149 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-routes b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-routes index 7faf49bd..fac9a5a2 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-routes +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-routes @@ -9,7 +9,7 @@ IPV6INIT=no MTU=1492 NM_CONTROLLED=yes DNS1=4.2.2.1 -DNS2=4.2.2.2 +DNS2=4.2.2.2#dns.name IPADDR=192.168.1.5 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 717ad1ac..728e8e96 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -6,7 +6,7 @@ ADDRESS1=44.55.66.77 NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 -OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14 rto_min 300 advmss 1300 quickack 1" +OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14 rto_min 300 advmss 1300 quickack 1 weight 5" ADDRESS2=44.55.66.78 NETMASK2=255.255.255.255 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 886a605f..40ff7c67 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 @@ -461,6 +461,7 @@ test_read_netmask_1(void) gs_free char *content = NULL; NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; NMIPAddress *ip4_addr; const char *FILENAME = TEST_IFCFG_DIR "/ifcfg-netmask-1"; @@ -470,12 +471,20 @@ test_read_netmask_1(void) g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "System netmask-1"); s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG); - g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); + g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.1"); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "192.0.2.2#adfs.afddsaf"); + ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0); g_assert(ip4_addr); g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "102.0.2.2"); g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 15); + s_ip6 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP6_CONFIG); + g_assert_cmpuint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "1::2"); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "1::3#dfdf.er"); + nmtst_assert_connection_verifies_without_normalization(connection); content = nmtst_file_get_contents(FILENAME); @@ -1356,6 +1365,7 @@ test_read_wired_static_routes(void) nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, 5); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); @@ -1390,6 +1400,10 @@ test_read_wired_static_routes(void) g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32); nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local"); nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 254); + + g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.2.2.1"); + g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "4.2.2.2#dns.name"); } static void @@ -2036,11 +2050,11 @@ test_read_wired_aliases_good(gconstpointer test_data) NULL}; const char *expected_address_3[] = {"192.168.1.5", "192.168.1.6", NULL}; const char *expected_label_0[] = { - NULL, - "aliasem0:1", - "aliasem0:2", - "aliasem0:99", - NULL, + NULL, + "aliasem0:1", + "aliasem0:2", + "aliasem0:99", + NULL, }; const char *expected_label_3[] = { NULL, @@ -2082,7 +2096,7 @@ test_read_wired_aliases_good(gconstpointer test_data) g_assert(ip4_addr != NULL); addr = nm_ip_address_get_address(ip4_addr); - g_assert(nm_utils_ipaddr_is_valid(AF_INET, addr)); + g_assert(nm_inet_is_valid(AF_INET, addr)); for (j = 0; j < expected_num_addresses; j++) { if (!g_strcmp0(addr, expected_address[j])) @@ -4266,6 +4280,7 @@ static void test_write_wired_static(void) { nmtst_auto_unlinkfile char *testfile = NULL; + nmtst_auto_unlinkfile char *route4file = NULL; nmtst_auto_unlinkfile char *route6file = NULL; gs_unref_object NMConnection *connection = NULL; gs_unref_object NMConnection *reread = NULL; @@ -4275,6 +4290,7 @@ test_write_wired_static(void) NMSettingIPConfig *s_ip6, *reread_s_ip6; NMIPAddress *addr; NMIPAddress *addr6; + NMIPRoute *route4; NMIPRoute *route6; GError *error = NULL; @@ -4379,6 +4395,13 @@ test_write_wired_static(void) nm_setting_ip_config_add_route(s_ip6, route6); nm_ip_route_unref(route6); + route4 = nm_ip_route_new(AF_INET, "1.1.1.1", 24, "1.2.3.4", 99, &error); + g_assert_no_error(error); + nm_ip_route_set_attribute(route4, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32(100)); + nm_ip_route_set_attribute(route4, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, g_variant_new_uint32(5)); + nm_setting_ip_config_add_route(s_ip4, route4); + nm_ip_route_unref(route4); + /* DNS servers */ nm_setting_ip_config_add_dns(s_ip6, "fade:0102:0103::face"); nm_setting_ip_config_add_dns(s_ip6, "cafe:ffff:eeee:dddd:cccc:bbbb:aaaa:feed"); @@ -4390,7 +4413,9 @@ test_write_wired_static(void) nmtst_assert_connection_verifies(connection); _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile); + route6file = utils_get_route6_path(testfile); + route4file = utils_get_route_path(testfile); reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL); @@ -7754,6 +7779,7 @@ test_read_vlan_interface(void) g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9"); g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 43); + g_assert_cmpstr(nm_setting_vlan_get_protocol(s_vlan), ==, "802.1ad"); g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_GVRP | NM_VLAN_FLAG_LOOSE_BINDING | NM_VLAN_FLAG_REORDER_HEADERS); @@ -7930,6 +7956,7 @@ test_read_vlan_flags_1(void) g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth9"); g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 44); + g_assert_cmpstr(nm_setting_vlan_get_protocol(s_vlan), ==, NULL); g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_LOOSE_BINDING | NM_VLAN_FLAG_REORDER_HEADERS); diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c index a1d6781b..3bdd78c9 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -451,7 +451,7 @@ update_ip4_setting_from_if_block(NMConnection *connection, if_block *block, GErr netmask_v); return FALSE; } else { - netmask_int = _nm_utils_ip4_netmask_to_prefix(tmp_mask); + netmask_int = nm_ip4_addr_netmask_to_prefix(tmp_mask); } } @@ -470,7 +470,7 @@ update_ip4_setting_from_if_block(NMConnection *connection, if_block *block, GErr /* gateway */ gateway_v = ifparser_getkey(block, "gateway"); if (gateway_v) { - if (!nm_utils_ipaddr_is_valid(AF_INET, gateway_v)) { + if (!nm_inet_is_valid(AF_INET, gateway_v)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -579,7 +579,7 @@ update_ip6_setting_from_if_block(NMConnection *connection, if_block *block, GErr gateway_v = ifparser_getkey(block, "gateway"); if (gateway_v) { - if (!nm_utils_ipaddr_is_valid(AF_INET6, gateway_v)) { + if (!nm_inet_is_valid(AF_INET6, gateway_v)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.h b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.h index edf1b317..570bf2a3 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.h +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.h @@ -11,7 +11,7 @@ #define NMS_TYPE_IFUPDOWN_PLUGIN (nms_ifupdown_plugin_get_type()) #define NMS_IFUPDOWN_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFUPDOWN_PLUGIN, NMSIfupdownPlugin)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_IFUPDOWN_PLUGIN, NMSIfupdownPlugin)) #define NMS_IFUPDOWN_PLUGIN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_IFUPDOWN_PLUGIN, NMSIfupdownPluginClass)) #define NMS_IS_IFUPDOWN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_IFUPDOWN_PLUGIN)) diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.h b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.h index 19e4122d..03a47526 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.h +++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.h @@ -14,7 +14,7 @@ #define NMS_TYPE_KEYFILE_PLUGIN (nms_keyfile_plugin_get_type()) #define NMS_KEYFILE_PLUGIN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_KEYFILE_PLUGIN, NMSKeyfilePlugin)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_KEYFILE_PLUGIN, NMSKeyfilePlugin)) #define NMS_KEYFILE_PLUGIN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_KEYFILE_PLUGIN, NMSKeyfilePluginClass)) #define NMS_IS_KEYFILE_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_KEYFILE_PLUGIN)) diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-storage.h b/src/core/settings/plugins/keyfile/nms-keyfile-storage.h index 8343cb2b..66521618 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-storage.h +++ b/src/core/settings/plugins/keyfile/nms-keyfile-storage.h @@ -14,7 +14,7 @@ #define NMS_TYPE_KEYFILE_STORAGE (nms_keyfile_storage_get_type()) #define NMS_KEYFILE_STORAGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorage)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorage)) #define NMS_KEYFILE_STORAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorageClass)) #define NMS_IS_KEYFILE_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_KEYFILE_STORAGE)) diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index f9ccc003..eb3754a2 100644 --- a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -36,7 +36,7 @@ routes9=1.1.1.9/19,0.0.0.0,0 route10=1.1.1.10/21,,0 routes10=1.1.1.10/20,,0 routes11=1.1.1.11/21,,21 -routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7,type=unicast +routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7,type=unicast,weight=5 routes12=1.2.3.4/32 routes12_options=type=local address30=1.2.3.30/24 diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index 47be3a5e..83019bab 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -311,6 +311,7 @@ test_read_valid_wired_connection(void) nmtst_assert_route_attribute_uint32(route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10); nmtst_assert_route_attribute_uint32(route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430); + nmtst_assert_route_attribute_uint32(route, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, 5); nmtst_assert_route_attribute_boolean(route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE); nmtst_assert_route_attribute_string(route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7"); nmtst_assert_route_attribute_string(route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "unicast"); @@ -495,6 +496,7 @@ test_write_wired_connection(void) g_assert_no_error(error); nm_ip_route_set_attribute(rt, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32(10)); nm_ip_route_set_attribute(rt, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32(1492)); + nm_ip_route_set_attribute(rt, NM_IP_ROUTE_ATTRIBUTE_WEIGHT, g_variant_new_uint32(5)); nm_ip_route_set_attribute(rt, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string("1.2.3.4")); g_assert(nm_setting_ip_config_add_route(s_ip4, rt)); nm_ip_route_unref(rt); @@ -2298,7 +2300,7 @@ test_read_missing_id_uuid(void) const char *FILENAME = TEST_KEYFILES_DIR "/Test_Missing_ID_UUID"; const char F[] = "keyfile\0" TEST_KEYFILES_DIR "/Test_Missing_ID_UUID"; - expected_uuid = nm_uuid_generate_from_strings("keyfile", FILENAME, NULL); + expected_uuid = nm_uuid_generate_from_strings_old("keyfile", FILENAME); expected_uuid2 = nm_uuid_generate_from_string_str(F, sizeof(F), NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1); diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index bd48ed92..c63a0058 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -153,16 +153,16 @@ nm_supplicant_config_add_option_with_type(NMSupplicantConfig *self, return FALSE; } - opt = g_slice_new0(ConfigOption); - opt->value = g_malloc(len + 1); - memcpy(opt->value, value, len); - opt->value[len] = '\0'; - - opt->len = len; - opt->type = type; + opt = g_slice_new(ConfigOption); + *opt = (ConfigOption){ + .value = nm_memdup_nul(value, len), + .len = len, + .type = type, + }; { char buf[255]; + memset(&buf[0], 0, sizeof(buf)); memcpy(&buf[0], opt->value, opt->len > 254 ? 254 : opt->len); nm_log_info(LOGD_SUPPLICANT, @@ -1379,12 +1379,24 @@ nm_supplicant_config_add_setting_8021x(NMSupplicantConfig *self, } phase1_auth_flags = nm_setting_802_1x_get_phase1_auth_flags(setting); - if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE)) + if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_ENABLE)) + g_string_append_printf(phase1, "%stls_disable_tlsv1_0=0", (phase1->len ? " " : "")); + else if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE)) g_string_append_printf(phase1, "%stls_disable_tlsv1_0=1", (phase1->len ? " " : "")); - if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE)) + if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_ENABLE)) + g_string_append_printf(phase1, "%stls_disable_tlsv1_1=0", (phase1->len ? " " : "")); + else if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE)) g_string_append_printf(phase1, "%stls_disable_tlsv1_1=1", (phase1->len ? " " : "")); - if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_DISABLE)) + if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_ENABLE)) + g_string_append_printf(phase1, "%stls_disable_tlsv1_2=0", (phase1->len ? " " : "")); + else if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_DISABLE)) g_string_append_printf(phase1, "%stls_disable_tlsv1_2=1", (phase1->len ? " " : "")); + if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_3_ENABLE)) + g_string_append_printf(phase1, "%stls_disable_tlsv1_3=0", (phase1->len ? " " : "")); + else if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_3_DISABLE)) + g_string_append_printf(phase1, "%stls_disable_tlsv1_3=1", (phase1->len ? " " : "")); + if (NM_FLAGS_HAS(phase1_auth_flags, NM_SETTING_802_1X_AUTH_FLAGS_TLS_DISABLE_TIME_CHECKS)) + g_string_append_printf(phase1, "%stls_disable_time_checks=1", (phase1->len ? " " : "")); if (phase1->len) { if (!add_string_val(self, phase1->str, "phase1", FALSE, NULL, error)) { diff --git a/src/core/supplicant/nm-supplicant-config.h b/src/core/supplicant/nm-supplicant-config.h index ee7f4dc8..063f7f55 100644 --- a/src/core/supplicant/nm-supplicant-config.h +++ b/src/core/supplicant/nm-supplicant-config.h @@ -16,7 +16,7 @@ #define NM_TYPE_SUPPLICANT_CONFIG (nm_supplicant_config_get_type()) #define NM_SUPPLICANT_CONFIG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_CONFIG, NMSupplicantConfig)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_CONFIG, NMSupplicantConfig)) #define NM_SUPPLICANT_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SUPPLICANT_CONFIG, NMSupplicantConfigClass)) #define NM_IS_SUPPLICANT_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SUPPLICANT_CONFIG)) diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index fa8b4e37..18525724 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -2647,7 +2647,7 @@ scan_request_cb(GObject *source, GAsyncResult *result, gpointer user_data) _LOGD("request-scan: request cancelled"); else { if (error) { - if (_nm_dbus_error_has_name(error, "fi.w1.wpa_supplicant1.Interface.ScanError")) + if (nm_dbus_error_is(error, "fi.w1.wpa_supplicant1.Interface.ScanError")) _LOGD("request-scan: could not get scan request result: %s", error->message); else { g_dbus_error_strip_remote_error(error); @@ -3174,7 +3174,7 @@ _signal_handle(NMSupplicantInterface *self, _set_p2p_assigned_addr(iface, addr_data, - _nm_utils_ip4_netmask_to_prefix(netmask)); + nm_ip4_addr_netmask_to_prefix(netmask)); } else { _LOGW("P2P: GroupStarted signaled invalid IP Address information"); } diff --git a/src/core/supplicant/nm-supplicant-interface.h b/src/core/supplicant/nm-supplicant-interface.h index 5ccb455c..b8d9b013 100644 --- a/src/core/supplicant/nm-supplicant-interface.h +++ b/src/core/supplicant/nm-supplicant-interface.h @@ -58,7 +58,7 @@ typedef enum { #define NM_TYPE_SUPPLICANT_INTERFACE (nm_supplicant_interface_get_type()) #define NM_SUPPLICANT_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface)) #define NM_SUPPLICANT_INTERFACE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass)) #define NM_IS_SUPPLICANT_INTERFACE(obj) \ diff --git a/src/core/supplicant/nm-supplicant-manager.c b/src/core/supplicant/nm-supplicant-manager.c index 2ec7db23..f6927500 100644 --- a/src/core/supplicant/nm-supplicant-manager.c +++ b/src/core/supplicant/nm-supplicant-manager.c @@ -450,7 +450,7 @@ _create_iface_dbus_call_get_interface_cb(GObject *source, GAsyncResult *result, char ifname[NMP_IFNAMSIZ]; if (handle->create_iface_try_count < CREATE_IFACE_TRY_COUNT_MAX - && _nm_dbus_error_has_name(error, NM_WPAS_ERROR_UNKNOWN_IFACE) + && nm_dbus_error_is(error, NM_WPAS_ERROR_UNKNOWN_IFACE) && nm_platform_if_indextoname(NM_PLATFORM_GET, handle->ifindex, ifname)) { /* Before, supplicant told us the interface existed. Was there a race? * Try again. */ @@ -500,7 +500,7 @@ _create_iface_dbus_call_create_interface_cb(GObject *source, nm_assert(handle->self); TRUE; }) - && _nm_dbus_error_has_name(error, NM_WPAS_ERROR_EXISTS_ERROR) + && nm_dbus_error_is(error, NM_WPAS_ERROR_EXISTS_ERROR) && nm_platform_if_indextoname(NM_PLATFORM_GET, handle->ifindex, ifname)) { self = handle->self; _LOGT("create-iface[" NM_HASH_OBFUSCATE_PTR_FMT diff --git a/src/core/supplicant/nm-supplicant-manager.h b/src/core/supplicant/nm-supplicant-manager.h index ab163b0d..b3284b70 100644 --- a/src/core/supplicant/nm-supplicant-manager.h +++ b/src/core/supplicant/nm-supplicant-manager.h @@ -12,7 +12,7 @@ #define NM_TYPE_SUPPLICANT_MANAGER (nm_supplicant_manager_get_type()) #define NM_SUPPLICANT_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManager)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManager)) #define NM_SUPPLICANT_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass)) #define NM_IS_SUPPLICANT_MANAGER(obj) \ diff --git a/src/core/supplicant/nm-supplicant-settings-verify.c b/src/core/supplicant/nm-supplicant-settings-verify.c index 9881c552..fc40bade 100644 --- a/src/core/supplicant/nm-supplicant-settings-verify.c +++ b/src/core/supplicant/nm-supplicant-settings-verify.c @@ -113,7 +113,11 @@ static const struct Opt opt_table[] = { "tls_disable_tlsv1_1=0", "tls_disable_tlsv1_1=1", "tls_disable_tlsv1_2=0", - "tls_disable_tlsv1_2=1", )), + "tls_disable_tlsv1_2=1", + "tls_disable_tlsv1_3=0", + "tls_disable_tlsv1_3=1", + "tls_disable_time_checks=0", + "tls_disable_time_checks=1", )), OPT_KEYWORD("phase2", NM_MAKE_STRV("auth=PAP", "auth=CHAP", @@ -277,12 +281,12 @@ nm_supplicant_settings_verify_setting(const char *key, const char *value, const } } - opt_idx = nm_utils_array_find_binary_search(opt_table, - sizeof(opt_table[0]), - G_N_ELEMENTS(opt_table), - &key, - nm_strcmp_p_with_data, - NULL); + opt_idx = nm_array_find_bsearch(opt_table, + G_N_ELEMENTS(opt_table), + sizeof(opt_table[0]), + &key, + nm_strcmp_p_with_data, + NULL); if (opt_idx < 0) { if (nm_streq(key, "mode")) { if (len != 1) diff --git a/src/core/tests/config/global-dns-good.conf b/src/core/tests/config/global-dns-good.conf new file mode 100644 index 00000000..6265a611 --- /dev/null +++ b/src/core/tests/config/global-dns-good.conf @@ -0,0 +1,13 @@ +# Good configuration, since there is a default domain section + +[global-dns] +searches=foo.com +options=timeout:5 + +[global-dns-domain-*] +servers=4.5.6.7 +options=myoption1 + +[global-dns-domain-test.com] +servers=1.2.3.4 +options=myoption2 diff --git a/src/core/tests/config/global-dns-options.conf b/src/core/tests/config/global-dns-options.conf new file mode 100644 index 00000000..0be17735 --- /dev/null +++ b/src/core/tests/config/global-dns-options.conf @@ -0,0 +1,5 @@ +# Good configuration, since there is no domain section + +[global-dns] +searches=foo.com +options=timeout:5 diff --git a/src/core/tests/config/nm-test-device.h b/src/core/tests/config/nm-test-device.h index 638177a0..48a53bf4 100644 --- a/src/core/tests/config/nm-test-device.h +++ b/src/core/tests/config/nm-test-device.h @@ -9,7 +9,8 @@ #include "devices/nm-device.h" #define NM_TYPE_TEST_DEVICE (nm_test_device_get_type()) -#define NM_TEST_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEST_DEVICE, NMTestDevice)) +#define NM_TEST_DEVICE(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEST_DEVICE, NMTestDevice)) #define NM_TEST_DEVICE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_TEST_DEVICE, NMTestDeviceClass)) #define NM_IS_TEST_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_TEST_DEVICE)) diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index 17a66b06..054b9003 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -370,7 +370,21 @@ test_config_global_dns(void) g_object_unref(config); - /* Check that a file without a default domain section gives a NULL configuration */ + /* Check that a file with a default domain section gives a good configuration */ + config = + setup_config(NULL, TEST_DIR "/global-dns-good.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_object_unref(config); + + /* Check that a file with options but no domains gives a good configuration */ + config = + setup_config(NULL, TEST_DIR "/global-dns-options.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_object_unref(config); + + /* Check that a file with a domain domain, but without a default one gives a NULL configuration */ config = setup_config(NULL, TEST_DIR "/global-dns-invalid.conf", "", NULL, "/no/such/dir", "", NULL); dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); @@ -1103,9 +1117,9 @@ test_config_set_values(void) const char *CONFIG_USER = BUILD_DIR "/test-set-values-user.conf"; const char *CONFIG_INTERN = BUILD_DIR "/test-set-values-intern.conf"; const char *atomic_section_prefixes[] = { - "atomic-prefix-1.", - "atomic-prefix-2.", - NULL, + "atomic-prefix-1.", + "atomic-prefix-2.", + NULL, }; g_assert(g_file_set_contents(CONFIG_USER, "", 0, NULL)); diff --git a/src/core/tests/test-core-with-expect.c b/src/core/tests/test-core-with-expect.c index de510c76..b05144ac 100644 --- a/src/core/tests/test-core-with-expect.c +++ b/src/core/tests/test-core-with-expect.c @@ -227,11 +227,11 @@ do_test_nm_utils_kill_child(void) { GLogLevelFlags fatal_mask; char *argv_watchdog[] = { - "bash", - "-c", - "sleep 4; " - "kill -KILL 0; #watchdog for #" TEST_TOKEN, - NULL, + "bash", + "-c", + "sleep 4; " + "kill -KILL 0; #watchdog for #" TEST_TOKEN, + NULL, }; char *argv1[] = { "bash", @@ -282,7 +282,7 @@ do_test_nm_utils_kill_child(void) pid4a = test_nm_utils_kill_child_spawn(argv4, TRUE); /* give processes time to start (and potentially block signals) ... */ - g_usleep(G_USEC_PER_SEC / 10); + g_usleep(G_USEC_PER_SEC / 5); fatal_mask = g_log_set_always_fatal(G_LOG_FATAL_MASK); @@ -338,12 +338,12 @@ do_test_nm_utils_kill_child(void) "(No child process*, 10) after sending no signal (0)"); test_nm_utils_kill_child_sync_do("test-s-3-2", pid3s, 0, 0, FALSE, NULL); - NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): waiting up to 1 milliseconds for " + NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): waiting up to 50 milliseconds for " "process to terminate normally after sending SIGTERM (15)..."); NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): sending SIGKILL..."); NMTST_EXPECT_NM_DEBUG("kill child process 'test-s-4' (*): after sending SIGTERM (15) and " "SIGKILL, process * exited by signal 9 (* usec elapsed)"); - test_nm_utils_kill_child_sync_do("test-s-4", pid4s, SIGTERM, 1, TRUE, &expected_signal_KILL); + test_nm_utils_kill_child_sync_do("test-s-4", pid4s, SIGTERM, 50, TRUE, &expected_signal_KILL); NMTST_EXPECT_NM_DEBUG("kill child process 'test-a-1-1' (*): wait for process to terminate " "after sending SIGTERM (15) (send SIGKILL in 3000 milliseconds)..."); @@ -528,27 +528,27 @@ test_nm_utils_array_remove_at_indexes(void) _remove_at_indexes_init_random_idx(idx, i_len, i_idx_len); g_array_set_size(array, i_len); for (i = 0; i < i_len; i++) - g_array_index(array, gssize, i) = i; + nm_g_array_index(array, gssize, i) = i; - nm_utils_array_remove_at_indexes(array, &g_array_index(idx, guint, 0), i_idx_len); + nm_utils_array_remove_at_indexes(array, nm_g_array_first_p(idx, guint), i_idx_len); g_hash_table_remove_all(unique); /* ensure that all the indexes are still unique */ for (i = 0; i < array->len; i++) - g_hash_table_add(unique, GUINT_TO_POINTER(g_array_index(array, gssize, i))); + g_hash_table_add(unique, GUINT_TO_POINTER(nm_g_array_index(array, gssize, i))); g_assert_cmpint(g_hash_table_size(unique), ==, array->len); for (i = 0; i < idx->len; i++) - g_hash_table_add(unique, GUINT_TO_POINTER(g_array_index(idx, guint, i))); + g_hash_table_add(unique, GUINT_TO_POINTER(nm_g_array_index(idx, guint, i))); g_assert_cmpint(g_hash_table_size(unique), ==, i_len); /* ensure proper sort order in array */ for (i = 0; i < array->len; i++) { - gssize i1 = g_array_index(array, gssize, i); + gssize i1 = nm_g_array_index(array, gssize, i); g_assert(i1 >= 0 && i1 < i_len); if (i > 0) { - gsize i0 = g_array_index(array, gssize, i - 1); + gsize i0 = nm_g_array_index(array, gssize, i - 1); g_assert_cmpint(i0, <, i1); } } diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index c260788e..887803bf 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -40,7 +40,7 @@ test_config_h(void) /*****************************************************************************/ -/* Reference implementation for nm_utils_ip6_address_clear_host_address. +/* Reference implementation for nm_ip6_addr_clear_host_address. * Taken originally from set_address_masked(), src/ndisc/nm-lndp-ndisc.c **/ static void @@ -95,14 +95,14 @@ test_nm_utils_ip6_address_clear_host_address(void) _randomize_in6_addr(&addr1, r); _randomize_in6_addr(&addr2, r); addr1 = addr_src; - nm_utils_ip6_address_clear_host_address(&addr2, &addr1, plen); + nm_ip6_addr_clear_host_address(&addr2, &addr1, plen); g_assert_cmpint(memcmp(&addr1, &addr_src, sizeof(struct in6_addr)), ==, 0); g_assert_cmpint(memcmp(&addr2, &addr_ref, sizeof(struct in6_addr)), ==, 0); /* test for self assignment/inplace update. */ _randomize_in6_addr(&addr1, r); addr1 = addr_src; - nm_utils_ip6_address_clear_host_address(&addr1, &addr1, plen); + nm_ip6_addr_clear_host_address(&addr1, &addr1, plen); g_assert_cmpint(memcmp(&addr1, &addr_ref, sizeof(struct in6_addr)), ==, 0); } } @@ -152,14 +152,14 @@ test_logging_error(void) static void _test_same_prefix(const char *a1, const char *a2, guint8 plen) { - struct in6_addr a = *nmtst_inet6_from_string(a1); - struct in6_addr b = *nmtst_inet6_from_string(a2); + struct in6_addr a = nmtst_inet6_from_string(a1); + struct in6_addr b = nmtst_inet6_from_string(a2); - g_assert(nm_utils_ip6_address_same_prefix(&a, &b, plen)); + g_assert(nm_ip6_addr_same_prefix(&a, &b, plen)); } static void -test_nm_utils_ip6_address_same_prefix(void) +test_nm_ip_addr_same_prefix(void) { guint n, i; const guint N = 100; @@ -202,7 +202,7 @@ again_plen: } else b = a; - result = nm_utils_ip6_address_same_prefix(&a.val, &b.val, plen); + result = nm_ip6_addr_same_prefix(&a.val, &b.val, plen); g_assert(result == is_same); g_assert(NM_IN_SET(result, TRUE, FALSE)); } @@ -214,12 +214,12 @@ again_plen: plen = nmtst_get_rand_uint32() % 129; memset(addrmask.ptr, 0xFF, sizeof(addrmask)); - nm_utils_ip6_address_clear_host_address(&addrmask.val, &addrmask.val, plen); + nm_ip6_addr_clear_host_address(&addrmask.val, &addrmask.val, plen); for (i = 0; i < sizeof(a); i++) b.ptr[i] = (a.ptr[i] & addrmask.ptr[i]) | (b.ptr[i] & ~addrmask.ptr[i]); - g_assert(nm_utils_ip6_address_same_prefix(&a.val, &b.val, plen) == TRUE); + g_assert(nm_ip6_addr_same_prefix(&a.val, &b.val, plen) == TRUE); } /* test#3 */ @@ -234,10 +234,10 @@ again_plen: continue; memset(addrmask.ptr, 0xFF, sizeof(addrmask)); - nm_utils_ip6_address_clear_host_address(&addrmask.val, &addrmask.val, plen); + nm_ip6_addr_clear_host_address(&addrmask.val, &addrmask.val, plen); memset(addrmask_bit.ptr, 0xFF, sizeof(addrmask_bit)); - nm_utils_ip6_address_clear_host_address(&addrmask_bit.val, &addrmask_bit.val, plen - 1); + nm_ip6_addr_clear_host_address(&addrmask_bit.val, &addrmask_bit.val, plen - 1); for (i = 0; i < sizeof(a); i++) b.ptr[i] = (a.ptr[i] & addrmask.ptr[i]) | (b.ptr[i] & ~addrmask.ptr[i]); @@ -254,7 +254,7 @@ again_plen: } g_assert(reached); - g_assert(nm_utils_ip6_address_same_prefix(&a.val, &b.val, plen) == FALSE); + g_assert(nm_ip6_addr_same_prefix(&a.val, &b.val, plen) == FALSE); } /* test#4 */ @@ -2594,10 +2594,9 @@ main(int argc, char **argv) g_test_add_func("/general/nm_strbuf_append", test_nm_utils_strbuf_append); - g_test_add_func("/general/nm_utils_ip6_address_clear_host_address", + g_test_add_func("/general/nm_ip6_addr_clear_host_address", test_nm_utils_ip6_address_clear_host_address); - g_test_add_func("/general/nm_utils_ip6_address_same_prefix", - test_nm_utils_ip6_address_same_prefix); + g_test_add_func("/general/nm_ip6_addr_same_prefix", test_nm_ip_addr_same_prefix); g_test_add_func("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff); g_test_add_func("/general/nm_utils_sysctl_ip_conf_path", test_nm_utils_sysctl_ip_conf_path); diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index a9ac4004..962b2eec 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -2,7 +2,7 @@ #include "src/core/nm-default-daemon.h" -#include <linux/if_addr.h> +#include "nm-compat-headers/linux/if_addr.h" #include "nm-l3cfg.h" #include "nm-l3-ipv4ll.h" @@ -339,6 +339,10 @@ test_l3cfg(gconstpointer test_data) _LOGD("test start (/l3cfg/%d)", TEST_IDX); + /* FIXME: https://bugzilla.redhat.com/show_bug.cgi?id=2165141 */ + g_test_skip("Skip: this test is currently known to fail (rhbz#2165141)"); + return; + if (nmtst_test_quick()) { gs_free char *msg = g_strdup_printf("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", @@ -418,7 +422,7 @@ test_l3cfg(gconstpointer test_data) nm_l3_config_data_add_address_6( l3cd, - NM_PLATFORM_IP6_ADDRESS_INIT(.address = *nmtst_inet6_from_string("1:2:3:4::45"), + NM_PLATFORM_IP6_ADDRESS_INIT(.address = nmtst_inet6_from_string("1:2:3:4::45"), .plen = 64, )); if (nmtst_get_rand_one_case_in(2)) @@ -572,7 +576,7 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, TestL3IPv4LLData *tdata) { - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; g_assert(NM_IS_L3CFG(l3cfg)); g_assert(tdata); @@ -593,9 +597,9 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg *l3cfg, if (tdata->f->test_idx == 2 && nmtst_get_rand_bool()) { tdata->addr_commit++; tdata->addr_commit_addr = nm_l3_ipv4ll_get_addr(tdata->l3ipv4ll); - g_assert(nm_utils_ip4_address_is_link_local(tdata->addr_commit_addr)); + g_assert(nm_ip4_addr_is_link_local(tdata->addr_commit_addr)); _LOGT("add address %s that passed ACD", - _nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); + nm_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); if (!nm_l3cfg_add_config(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), TEST_L3_IPV4LL_TAG(tdata, 1), nmtst_get_rand_bool(), @@ -630,9 +634,9 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg *l3cfg, if (tdata->addr_commit > 0) { g_assert_cmpint(tdata->addr_commit, ==, 1); tdata->addr_commit--; - g_assert(nm_utils_ip4_address_is_link_local(tdata->addr_commit_addr)); + g_assert(nm_ip4_addr_is_link_local(tdata->addr_commit_addr)); _LOGT("remove address %s that previously passed ACD", - _nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); + nm_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); if (!nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), TEST_L3_IPV4LL_TAG(tdata, 1))) g_assert_not_reached(); @@ -663,7 +667,7 @@ test_l3_ipv4ll(gconstpointer test_data) gint64 start_time_msec; gint64 total_poll_time_msec; nm_auto_remove_l3ipv4ll_registration NML3IPv4LLRegistration *l3ipv4ll_reg = NULL; - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; _LOGD("test start (/l3-ipv4ll/%d)", TEST_IDX); @@ -733,12 +737,12 @@ test_l3_ipv4ll(gconstpointer test_data) if (tdata->f->test_idx == 2 && nmtst_get_rand_one_case_in(3)) { in_addr_t a = nm_l3_ipv4ll_get_addr(l3ipv4ll); - g_assert(nm_utils_ip4_address_is_link_local(a)); + g_assert(nm_ip4_addr_is_link_local(a)); _test_l3_ipv4ll_maybe_add_addr_4(tdata, tdata->f->ifindex1, 2, &tdata->add_conflict_done, - _nm_utils_inet4_ntop(a, sbuf_addr)); + nm_inet4_ntop(a, sbuf_addr)); g_assert_cmpint(tdata->f->hwaddr1.len, ==, sizeof(NMEtherAddr)); acd_defender_2 = nmtstp_acd_defender_new(tdata->f->ifindex1, a, &tdata->f->hwaddr1.ether_addr); @@ -768,12 +772,11 @@ test_l3_ipv4ll(gconstpointer test_data) if (tdata->addr_commit == 1 && !tdata->add_conflict_checked) { tdata->add_conflict_checked = TRUE; - _test_l3_ipv4ll_maybe_add_addr_4( - tdata, - tdata->f->ifindex1, - 2, - &tdata->add_conflict_done, - _nm_utils_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); + _test_l3_ipv4ll_maybe_add_addr_4(tdata, + tdata->f->ifindex1, + 2, + &tdata->add_conflict_done, + nm_inet4_ntop(tdata->addr_commit_addr, sbuf_addr)); if (tdata->add_conflict_done) total_poll_time_msec += L3IPV4LL_ACD_TIMEOUT_MSEC / 2; g_assert_cmpint(tdata->f->hwaddr1.len, ==, sizeof(NMEtherAddr)); @@ -986,7 +989,7 @@ test_l3_ipv6ll(gconstpointer test_data) nmtstp_ip6_address_add(tdata->f->platform, -1, tdata->f->ifindex1, - *nmtst_inet6_from_string(_LLADDR_TEST1), + nmtst_inet6_from_string(_LLADDR_TEST1), 64, in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c index cf31ec33..1b0b7f65 100644 --- a/src/core/tests/test-systemd.c +++ b/src/core/tests/test-systemd.c @@ -12,21 +12,6 @@ /*****************************************************************************/ -static void -test_lldp_create(void) -{ - sd_lldp_rx *lldp = NULL; - int r; - - r = sd_lldp_rx_new(&lldp); - g_assert(r == 0); - g_assert(lldp); - - sd_lldp_rx_unref(lldp); -} - -/*****************************************************************************/ - typedef struct { GMainLoop *mainloop; sd_event_source *event_source; @@ -105,7 +90,6 @@ main(int argc, char **argv) { nmtst_init(&argc, &argv, TRUE); - g_test_add_func("/systemd/lldp/create", test_lldp_create); g_test_add_func("/systemd/sd-event", test_sd_event); return g_test_run(); diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index bbb73550..d7102a12 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -99,6 +99,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMVpnConnection, PROP_VPN_STATE, PROP_BANNER, #define PROP_IP4_CONFIG 2000 #define PROP_IP6_CONFIG 2001 #define PROP_MASTER 2002 +#define PROP_CONTROLLER 2003 ); typedef struct { @@ -107,14 +108,15 @@ typedef struct { NMIPAddr gw_internal; NMIPAddr gw_external; - /* Whether this address family is enabled. If not, then we won't have a l3cd instance, - * but the activation for this address family is still complete. */ - bool enabled : 1; + /* Whether VPN auto-configuration is enabled in the connection profile for + * this address family. */ + bool method_auto : 1; - /* Whether this address family is ready. This means we received the IP configuration. - * Usually this implies we also have a corresponding l3cd, but that might not be the - * case if this address family is disabled. */ - bool conf_ready : 1; + /* Whether VPN auto-configuration is enabled, in the connection profile AND + * in the configuration reported by the VPN. If not, then we won't have a + * l3cd instance, but the activation for this address family is still + * complete. */ + bool enabled : 1; } IPData; typedef struct { @@ -1217,7 +1219,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, if (!nm_ip_addr_is_null(addr_family, gw)) { nm_ip_addr_set(addr_family, &parent_gw, gw); has_parent_gw = TRUE; - } else if (nm_utils_ip_is_site_local(addr_family, vpn_gw)) + } else if (nm_ip_addr_is_site_local(addr_family, vpn_gw)) has_parent_gw = TRUE; else if ((obj = nm_device_get_best_default_route(parent_device, addr_family)) && nm_ip_addr_is_null( @@ -1296,6 +1298,17 @@ _l3cfg_l3cd_gw_extern_update(NMVpnConnection *self) changed = FALSE; for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + NMSettingIPConfig *s_ip; + + s_ip = nm_connection_get_setting_ip_config(_get_applied_connection(self), addr_family); + if (s_ip && nm_setting_ip_config_get_auto_route_ext_gw(s_ip) == NM_TERNARY_FALSE) { + _LOGD("IPv%c route to the external gateway have been deactivated via auto-route-ext-gw " + "setting", + nm_utils_addr_family_to_char(addr_family)); + continue; + } + if (_parent_device_l3cd_add_gateway_route( l3cd, IS_IPv4 ? AF_INET : AF_INET6, @@ -1870,9 +1883,16 @@ _dbus_signal_config_cb(NMVpnConnection *self, GVariant *dict) else priv->ip_data_6.enabled = FALSE; - _LOGD("config: reply received (IPv4:%s, IPv6:%s)", + _LOGD("config: reply received (IPv4:%s(%s), IPv6:%s(%s))", priv->ip_data_4.enabled ? "on" : "off", - priv->ip_data_6.enabled ? "on" : "off"); + priv->ip_data_4.method_auto ? "auto" : "disabled", + priv->ip_data_4.enabled ? "on" : "off", + priv->ip_data_6.method_auto ? "auto" : "disabled"); + + if (!priv->ip_data_4.method_auto) + priv->ip_data_4.enabled = FALSE; + if (!priv->ip_data_6.method_auto) + priv->ip_data_6.enabled = FALSE; if (priv->vpn_state == STATE_CONNECT) _set_vpn_state(self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); @@ -1936,7 +1956,8 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict return; } - priv->ip_data_4.enabled = TRUE; + if (priv->ip_data_4.method_auto) + priv->ip_data_4.enabled = TRUE; priv->ip_data_6.enabled = FALSE; } } else { @@ -1953,6 +1974,11 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict _set_vpn_state(self, STATE_IP_CONFIG_GET, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); } + if (!priv->ip_data_x[IS_IPv4].enabled) { + _check_complete(self, TRUE); + return; + } + ip_ifindex = nm_vpn_connection_get_ip_ifindex(self, TRUE); if (ip_ifindex <= 0) g_return_if_reached(); @@ -2011,14 +2037,14 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict if (IS_IPv4) { if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &var_iter)) { while (g_variant_iter_next(var_iter, "u", &u32)) - nm_l3_config_data_add_nameserver(l3cd, addr_family, &u32); + nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &u32, NULL); g_variant_iter_free(var_iter); } } else { if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DNS, "aay", &var_iter)) { while (g_variant_iter_next(var_iter, "@ay", &v)) { if (nm_ip_addr_set_from_variant(AF_INET6, &v_addr, v, NULL)) - nm_l3_config_data_add_nameserver(l3cd, addr_family, &v_addr); + nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &v_addr, NULL); g_variant_unref(v); } g_variant_iter_free(var_iter); @@ -2104,9 +2130,8 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict if (plen > 32) break; - route.r4.plen = plen; - route.r4.network = - nm_utils_ip4_address_clear_host_address(route.r4.network, plen); + route.r4.plen = plen; + route.r4.network = nm_ip4_addr_clear_host_address(route.r4.network, plen); if (priv->ip_data_4.gw_external.addr4 && route.r4.network == priv->ip_data_4.gw_external.addr4 @@ -2146,9 +2171,7 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict nm_ip_addr_set_from_variant(AF_INET6, &route.r6.gateway, next_hop, NULL); - nm_utils_ip6_address_clear_host_address(&route.r6.network, - &route.r6.network, - route.r6.plen); + nm_ip6_addr_clear_host_address(&route.r6.network, &route.r6.network, route.r6.plen); if (!IN6_IS_ADDR_UNSPECIFIED(&priv->ip_data_6.gw_external.addr6) && IN6_ARE_ADDR_EQUAL(&route.r6.network, &priv->ip_data_6.gw_external.addr6) @@ -2761,6 +2784,11 @@ nm_vpn_connection_activate(NMVpnConnection *self, NMVpnPluginInfo *plugin_info) _LOGI("starting %s", nm_vpn_plugin_info_get_name(plugin_info)); + priv->ip_data_4.method_auto = nm_streq0(nm_utils_get_ip_config_method(connection, AF_INET), + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + priv->ip_data_6.method_auto = nm_streq0(nm_utils_get_ip_config_method(connection, AF_INET6), + NM_SETTING_IP6_CONFIG_METHOD_AUTO); + priv->connection_can_persist = nm_setting_vpn_get_persistent(s_vpn); priv->plugin_info = g_object_ref(plugin_info); @@ -2841,17 +2869,11 @@ device_changed(NMActiveConnection *active, NMDevice *new_device, NMDevice *old_d _l3cfg_clear(self, l3cfg_old); priv->ifindex_dev = ifindex; - if (ifindex > 0) { - priv->l3cfg_dev = nm_netns_l3cfg_acquire(priv->netns, ifindex); - g_signal_connect(priv->l3cfg_dev, - NM_L3CFG_SIGNAL_NOTIFY, - G_CALLBACK(_l3cfg_notify_cb), - self); - priv->l3cfg_commit_type_dev = nm_l3cfg_commit_type_register(priv->l3cfg_dev, - NM_L3_CFG_COMMIT_TYPE_UPDATE, - NULL, - "vpn"); - } + + priv->l3cfg_dev = nm_netns_l3cfg_acquire(priv->netns, ifindex); + g_signal_connect(priv->l3cfg_dev, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_l3cfg_notify_cb), self); + priv->l3cfg_commit_type_dev = + nm_l3cfg_commit_type_register(priv->l3cfg_dev, NM_L3_CFG_COMMIT_TYPE_UPDATE, NULL, "vpn"); if (_l3cfg_l3cd_gw_extern_update(self)) nm_l3cfg_commit_on_idle_schedule(priv->l3cfg_dev, NM_L3_CFG_COMMIT_TYPE_AUTO); @@ -2878,6 +2900,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_IP6_CONFIG: nm_dbus_utils_g_value_set_object_path(value, priv->ip_data_6.ip_config); break; + case PROP_CONTROLLER: case PROP_MASTER: nm_dbus_utils_g_value_set_object_path( value, @@ -3044,6 +3067,9 @@ nm_vpn_connection_class_init(NMVpnConnectionClass *klass) g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + g_object_class_override_property(object_class, + PROP_CONTROLLER, + NM_ACTIVE_CONNECTION_CONTROLLER); g_object_class_override_property(object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER); g_object_class_override_property(object_class, PROP_IP4_CONFIG, diff --git a/src/core/vpn/nm-vpn-connection.h b/src/core/vpn/nm-vpn-connection.h index 51e2e500..f9c38322 100644 --- a/src/core/vpn/nm-vpn-connection.h +++ b/src/core/vpn/nm-vpn-connection.h @@ -15,7 +15,7 @@ #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type()) #define NM_VPN_CONNECTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) #define NM_VPN_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_VPN_CONNECTION, NMVpnConnectionClass)) #define NM_IS_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_VPN_CONNECTION)) diff --git a/src/core/vpn/nm-vpn-manager.h b/src/core/vpn/nm-vpn-manager.h index 41ecb8d2..cd691dd1 100644 --- a/src/core/vpn/nm-vpn-manager.h +++ b/src/core/vpn/nm-vpn-manager.h @@ -10,7 +10,8 @@ #include "nm-vpn-connection.h" #define NM_TYPE_VPN_MANAGER (nm_vpn_manager_get_type()) -#define NM_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_MANAGER, NMVpnManager)) +#define NM_VPN_MANAGER(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VPN_MANAGER, NMVpnManager)) #define NM_VPN_MANAGER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_VPN_MANAGER, NMVpnManagerClass)) #define NM_IS_VPN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_VPN_MANAGER)) |