diff options
| author | Michael Biebl <biebl@debian.org> | 2025-09-12 19:47:12 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2025-09-12 19:47:12 +0200 |
| commit | b1655e06d992cd690c0b74f8292ef62f669ecdb1 (patch) | |
| tree | 8b74f02013d9507317e19f4f415c218d619269f8 /src | |
| parent | 6a11a05e66efbf567f52e6a354540f18f3e023b6 (diff) | |
| parent | bc5f10851bffd6af1c2855635be7a28b6dba3195 (diff) | |
Update upstream source from tag 'upstream/1.54.1'
Update to upstream version '1.54.1' with Debian dir e162c0a8d88871855453474e7d890fafe7ea06aa
Diffstat (limited to 'src')
33 files changed, 1084 insertions, 95 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 673d2361..39e68e96 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -52,8 +52,7 @@ NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \ NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_USE_CARRIER, \ NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, \ - NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, \ - NM_SETTING_BOND_OPTION_LACP_ACTIVE + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX #define OPTIONS_REAPPLY_FULL \ OPTIONS_REAPPLY_SUBSET, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, \ diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index f6057e52..79b1076d 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -9164,6 +9164,10 @@ is_available(NMDevice *self, NMDeviceCheckDevAvailableFlags flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + /* unrealized software devices are always available, hardware devices never */ + if (!nm_device_is_real(self)) + return nm_device_is_software(self); + if (priv->carrier || priv->ignore_carrier) return TRUE; @@ -14696,13 +14700,15 @@ impl_device_delete(NMDBusObject *obj, NULL); } -static void +static gboolean _device_activate(NMDevice *self, NMActRequest *req) { NMConnection *connection; - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); + /* Returns TRUE on success, FALSE if the activation request could not be started */ + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE); nm_assert(nm_device_is_real(self)); /* Ensure the activation request is still valid; the controller may have @@ -14710,7 +14716,7 @@ _device_activate(NMDevice *self, NMActRequest *req) */ if (nm_active_connection_get_state(NM_ACTIVE_CONNECTION(req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) - return; + return FALSE; if (!nm_device_get_managed(self, FALSE)) { /* It's unclear why the device would be unmanaged at this point. @@ -14721,7 +14727,7 @@ _device_activate(NMDevice *self, NMActRequest *req) nm_active_connection_set_state_fail((NMActiveConnection *) req, NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, NULL); - return; + return FALSE; } connection = nm_act_request_get_applied_connection(req); @@ -14737,6 +14743,8 @@ _device_activate(NMDevice *self, NMActRequest *req) act_request_set(self, req); nm_device_activate_schedule_stage1_device_prepare(self, FALSE); + + return TRUE; } static void @@ -14756,7 +14764,9 @@ _carrier_wait_check_queued_act_request(NMDevice *self) _LOGD(LOGD_DEVICE, "Activate queued activation request as we now have carrier"); queued_req = g_steal_pointer(&priv->queued_act_request); - _device_activate(self, queued_req); + if (!_device_activate(self, queued_req)) { + delete_on_deactivate_check_and_schedule(self); + } } } @@ -17534,7 +17544,8 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gs_unref_object NMActRequest *queued_req = NULL; queued_req = g_steal_pointer(&priv->queued_act_request); - _device_activate(self, queued_req); + if (!_device_activate(self, queued_req)) + delete_on_deactivate_check_and_schedule(self); } break; case NM_DEVICE_STATE_ACTIVATED: diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 06eee142..b890b110 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -196,7 +196,8 @@ static void periodic_update(NMDeviceWifi *self); static void ap_add_remove(NMDeviceWifi *self, gboolean is_adding, NMWifiAP *ap, - gboolean recheck_available_connections); + gboolean recheck_available_connections, + gboolean recheck_auto_activate); static void _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset); @@ -714,7 +715,10 @@ update_seen_bssids_cache(NMDeviceWifi *self, NMWifiAP *ap) } static void -set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_connections) +set_current_ap(NMDeviceWifi *self, + NMWifiAP *new_ap, + gboolean recheck_available_connections, + gboolean recheck_auto_activate) { NMDeviceWifiPrivate *priv; NMWifiAP *old_ap; @@ -741,7 +745,11 @@ set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_ /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ if (NM_IN_SET(mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP) || nm_wifi_ap_get_fake(old_ap)) - ap_add_remove(self, FALSE, old_ap, recheck_available_connections); + ap_add_remove(self, + FALSE, + old_ap, + recheck_available_connections, + recheck_auto_activate); g_object_unref(old_ap); } @@ -814,7 +822,8 @@ static void ap_add_remove(NMDeviceWifi *self, gboolean is_adding, /* or else removing */ NMWifiAP *ap, - gboolean recheck_available_connections) + gboolean recheck_available_connections, + gboolean recheck_auto_activate) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); @@ -845,13 +854,14 @@ ap_add_remove(NMDeviceWifi *self, nm_dbus_object_clear_and_unexport(&ap); } - nm_device_recheck_auto_activate_schedule(NM_DEVICE(self)); + if (recheck_auto_activate) + nm_device_recheck_auto_activate_schedule(NM_DEVICE(self)); if (recheck_available_connections) nm_device_recheck_available_connections(NM_DEVICE(self)); } static void -remove_all_aps(NMDeviceWifi *self) +remove_all_aps(NMDeviceWifi *self, gboolean disposing) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); NMWifiAP *ap; @@ -859,12 +869,13 @@ remove_all_aps(NMDeviceWifi *self) if (c_list_is_empty(&priv->aps_lst_head)) return; - set_current_ap(self, NULL, FALSE); + set_current_ap(self, NULL, FALSE, !disposing); while ((ap = c_list_first_entry(&priv->aps_lst_head, NMWifiAP, aps_lst))) - ap_add_remove(self, FALSE, ap, FALSE); + ap_add_remove(self, FALSE, ap, FALSE, !disposing); - nm_device_recheck_available_connections(NM_DEVICE(self)); + if (!disposing) + nm_device_recheck_available_connections(NM_DEVICE(self)); } static gboolean @@ -951,7 +962,7 @@ deactivate(NMDevice *device) priv->rate = 0; - set_current_ap(self, NULL, TRUE); + set_current_ap(self, NULL, TRUE, TRUE); if (!wake_on_wlan_restore(self)) _LOGW(LOGD_DEVICE | LOGD_WIFI, "Cannot unconfigure WoWLAN."); @@ -2000,7 +2011,7 @@ supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, if (nm_wifi_ap_set_fake(found_ap, TRUE)) _ap_dump(self, LOGL_DEBUG, found_ap, "updated", 0); } else { - ap_add_remove(self, FALSE, found_ap, TRUE); + ap_add_remove(self, FALSE, found_ap, TRUE, TRUE); schedule_ap_list_dump(self); } return; @@ -2043,7 +2054,7 @@ supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, } } - ap_add_remove(self, TRUE, ap, TRUE); + ap_add_remove(self, TRUE, ap, TRUE, TRUE); } /* Update the current AP if the supplicant notified a current BSS change @@ -2268,7 +2279,7 @@ link_timeout_cb(gpointer user_data) if (nm_device_get_state(device) != NM_DEVICE_STATE_ACTIVATED) return FALSE; - set_current_ap(self, NULL, TRUE); + set_current_ap(self, NULL, TRUE, TRUE); nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, @@ -2684,7 +2695,7 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, } } - set_current_ap(self, new_ap, TRUE); + set_current_ap(self, new_ap, TRUE, TRUE); req = nm_device_get_act_request(NM_DEVICE(self)); if (req) { @@ -3118,7 +3129,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) priv->mode = _NM_802_11_MODE_AP; /* Scanning not done in AP mode; clear the scan list */ - remove_all_aps(self); + remove_all_aps(self, FALSE); } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) priv->mode = _NM_802_11_MODE_MESH; _notify(self, PROP_MODE); @@ -3155,14 +3166,14 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_wifi_ap_set_address(ap_fake, nm_device_get_hw_address(device)); g_object_freeze_notify(G_OBJECT(self)); - ap_add_remove(self, TRUE, ap_fake, TRUE); + ap_add_remove(self, TRUE, ap_fake, TRUE, TRUE); g_object_thaw_notify(G_OBJECT(self)); ap = ap_fake; } _scan_notify_allowed(self, NM_TERNARY_DEFAULT); - set_current_ap(self, ap, FALSE); + set_current_ap(self, ap, FALSE, TRUE); nm_active_connection_set_specific_object(NM_ACTIVE_CONNECTION(req), nm_dbus_object_get_path(NM_DBUS_OBJECT(ap))); return NM_ACT_STAGE_RETURN_SUCCESS; @@ -3528,7 +3539,7 @@ device_state_changed(NMDevice *device, cleanup_association_attempt(self, TRUE); cleanup_supplicant_failures(self); - remove_all_aps(self); + remove_all_aps(self, FALSE); } switch (new_state) { @@ -3566,7 +3577,7 @@ device_state_changed(NMDevice *device, } if (clear_aps) - remove_all_aps(self); + remove_all_aps(self, FALSE); _scan_notify_allowed(self, NM_TERNARY_DEFAULT); } @@ -3808,7 +3819,7 @@ dispose(GObject *object) g_clear_object(&priv->sup_mgr); - remove_all_aps(self); + remove_all_aps(self, TRUE); if (priv->p2p_device) { /* Destroy the P2P device. */ diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index d47590dc..57e73226 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -586,7 +586,11 @@ add_dns_domains(GPtrArray *array, } static void -merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3ConfigData *l3cd) +merge_one_l3cd(NMResolvConfData *rc, + int addr_family, + int ifindex, + const NML3ConfigData *l3cd, + gboolean ignore_searches_and_options) { char buf[NM_INET_ADDRSTRLEN + 50]; gboolean has_trust_ad; @@ -624,30 +628,32 @@ merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3Con add_string_item(rc->nameservers, buf, TRUE); } - add_dns_domains(rc->searches, addr_family, l3cd, FALSE, TRUE); + if (!ignore_searches_and_options) { + add_dns_domains(rc->searches, addr_family, l3cd, FALSE, TRUE); - has_trust_ad = FALSE; - strarr = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num); - for (i = 0; i < num; i++) { - const char *option = strarr[i]; + has_trust_ad = FALSE; + strarr = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num); + for (i = 0; i < num; i++) { + const char *option = strarr[i]; - if (nm_streq(option, NM_SETTING_DNS_OPTION_TRUST_AD)) { - has_trust_ad = TRUE; - continue; + if (nm_streq(option, NM_SETTING_DNS_OPTION_TRUST_AD)) { + has_trust_ad = TRUE; + continue; + } + add_dns_option_item(rc->options, option); } - add_dns_option_item(rc->options, option); - } - if (num_nameservers == 0) { - /* If the @l3cd contributes no DNS servers, ignore whether trust-ad is set or unset - * for this @l3cd. */ - } else if (has_trust_ad) { - /* We only set has_trust_ad to TRUE, if all IP configs agree (or don't contribute). - * Once set to FALSE, it doesn't get reset. */ - if (rc->has_trust_ad == NM_TERNARY_DEFAULT) - rc->has_trust_ad = NM_TERNARY_TRUE; - } else - rc->has_trust_ad = NM_TERNARY_FALSE; + if (num_nameservers == 0) { + /* If the @l3cd contributes no DNS servers, ignore whether trust-ad is set or unset + * for this @l3cd. */ + } else if (has_trust_ad) { + /* We only set has_trust_ad to TRUE, if all IP configs agree (or don't contribute). + * Once set to FALSE, it doesn't get reset. */ + if (rc->has_trust_ad == NM_TERNARY_DEFAULT) + rc->has_trust_ad = NM_TERNARY_TRUE; + } else + rc->has_trust_ad = NM_TERNARY_FALSE; + } if (addr_family == AF_INET) { const in_addr_t *nis_servers; @@ -1231,12 +1237,15 @@ compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[ { nm_auto_free_checksum GChecksum *sum = NULL; NMDnsConfigIPData *ip_data; + gboolean has_global_dns_section = FALSE; sum = g_checksum_new(G_CHECKSUM_SHA1); nm_assert(HASH_LEN == g_checksum_type_get_length(G_CHECKSUM_SHA1)); - if (global) + if (global) { nm_global_dns_config_update_checksum(global, sum); + has_global_dns_section = nm_global_dns_has_global_dns_section(global); + } if (!global || !nm_global_dns_config_lookup_domain(global, "*")) { const CList *head; @@ -1248,7 +1257,8 @@ compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[ nm_l3_config_data_hash_dns(ip_data->l3cd, sum, ip_data->addr_family, - ip_data->ip_config_type); + ip_data->ip_config_type, + has_global_dns_section); } } @@ -1264,6 +1274,9 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) const char *const *servers; guint i; + /* Global config must be processed before connections' config */ + nm_assert(rc->nameservers->len == 0); + if (!global_conf) return FALSE; @@ -1351,12 +1364,17 @@ _collect_resolv_conf_data(NMDnsManager *self, .nis_servers = g_ptr_array_new(), .has_trust_ad = NM_TERNARY_DEFAULT, }; + gboolean has_global_dns_section = FALSE; priv = NM_DNS_MANAGER_GET_PRIVATE(self); - if (global_config) + if (global_config) { merge_global_dns_config(&rc, global_config); + has_global_dns_section = nm_global_dns_has_global_dns_section(global_config); + } + /* If global nameservers are defined, no DNS configs are used from connections at all, + * including searches and options. */ 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; @@ -1390,8 +1408,16 @@ _collect_resolv_conf_data(NMDnsManager *self, skip ? "<SKIP>" : "", get_nameserver_list(ip_data->addr_family, ip_data->l3cd, &tmp_strbuf)); - if (!skip) - merge_one_l3cd(&rc, ip_data->addr_family, ip_data->data->ifindex, ip_data->l3cd); + if (!skip) { + /* Merge the configs from connections. However, if there was a [global-dns] + * it overwrites searches and options from the connections, thus we only + * merge the nameservers. */ + merge_one_l3cd(&rc, + ip_data->addr_family, + ip_data->data->ifindex, + ip_data->l3cd, + has_global_dns_section); + } } } diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index 5a84a2c8..461fd8ed 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -50,9 +50,9 @@ struct _NMGlobalDnsConfig { char **options; GHashTable *domains; const char **domain_list; - gboolean internal; char *cert_authority; NMDnsResolveMode resolve_mode; + gboolean internal; }; /*****************************************************************************/ @@ -941,6 +941,14 @@ next: /*****************************************************************************/ +gboolean +nm_global_dns_has_global_dns_section(const NMGlobalDnsConfig *dns_config) +{ + g_return_val_if_fail(dns_config, FALSE); + + return dns_config->searches != NULL || dns_config->options != NULL; +} + const char *const * nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config) { @@ -1236,6 +1244,7 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) gs_free char *cert_authority = NULL; gs_free char *resolve_mode = NULL; NMDnsResolveMode parsed_resolve_mode; + gboolean has_global_dns_section; if (internal) { group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS; @@ -1386,6 +1395,22 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) return NULL; } + /* Defining [global-dns-domain-*] implies defining [global-dns] too (maybe empty) */ + if (default_found) + has_global_dns_section = TRUE; + else + has_global_dns_section = g_key_file_has_group(keyfile, group); + + /* If there exist a [global-dns] section, always initialize "searches" and "options" so + * they appear in D-Bus. Clients can use this to know if it's defined, so they can know + * if DNS configs from connections are relevant or not. */ + if (has_global_dns_section) { + if (!dns_config->searches) + dns_config->searches = nm_strv_empty_new(); + if (!dns_config->options) + dns_config->options = nm_strv_empty_new(); + } + dns_config->internal = internal; global_dns_config_seal_domains(dns_config); return dns_config; @@ -1606,17 +1631,6 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) g_variant_unref(val); } - /* An empty value is valid and clears the internal configuration */ - if (!nm_global_dns_config_is_empty(dns_config) - && !nm_global_dns_config_lookup_domain(dns_config, "*")) { - g_set_error_literal(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Global DNS configuration is missing the default domain"); - nm_global_dns_config_free(dns_config); - return NULL; - } - global_dns_config_seal_domains(dns_config); return dns_config; } diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h index d764a7c4..6666ccf6 100644 --- a/src/core/nm-config-data.h +++ b/src/core/nm-config-data.h @@ -274,6 +274,7 @@ gboolean nm_config_data_is_intern_atomic_group(const NMConfigData *self, const c GKeyFile *nm_config_data_clone_keyfile_intern(const NMConfigData *self); +gboolean nm_global_dns_has_global_dns_section(const NMGlobalDnsConfig *dns_config); const char *const *nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config); const char *const *nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config); const char *nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config); diff --git a/src/core/nm-config.c b/src/core/nm-config.c index a55d2d13..d1f2bbed 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -18,6 +18,7 @@ #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-intern/nm-keyfile-internal.h" #include "libnm-core-intern/nm-keyfile-utils.h" +#include "libnm-glib-aux/nm-keyfile-aux.h" #define DEFAULT_CONFIG_MAIN_FILE NMCONFDIR "/NetworkManager.conf" #define DEFAULT_CONFIG_DIR NMCONFDIR "/conf.d" @@ -1046,6 +1047,10 @@ read_config(GKeyFile *keyfile, /* internal groups cannot be set by user configuration. */ continue; } + + if (!g_key_file_has_group(keyfile, group)) + nm_key_file_add_group(keyfile, group); + keys = g_key_file_get_keys(kf, group, &nkeys, NULL); if (!keys) continue; @@ -1639,6 +1644,12 @@ intern_config_read(const char *filename, ""); } + if (!g_key_file_has_group(keyfile_intern, group)) { + nm_key_file_add_group(keyfile_intern, group); + if (is_intern) + has_intern = TRUE; + } + for (k = 0; keys[k]; k++) { gs_free char *value_set = NULL; const char *key = keys[k]; @@ -1823,6 +1834,9 @@ intern_config_write(const char *filename, } } + if (!g_key_file_has_group(keyfile, group)) + nm_key_file_add_group(keyfile, group); + for (k = 0; keys[k]; k++) { const char *key = keys[k]; gs_free char *value_set = NULL; diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 20623145..666aa8a3 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -3139,7 +3139,8 @@ void nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, GChecksum *sum, int addr_family, - NMDnsIPConfigType dns_ip_config_type) + NMDnsIPConfigType dns_ip_config_type, + gboolean ignore_searches_and_options) { guint i; int val; @@ -3178,16 +3179,18 @@ nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, 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; - } + if (!ignore_searches_and_options) { + 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; + 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); diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index bcb6af67..265e126d 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -615,6 +615,7 @@ nmtst_l3_config_data_get_best_gateway(const NML3ConfigData *self, int addr_famil void nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, GChecksum *sum, int addr_family, - NMDnsIPConfigType dns_ip_config_type); + NMDnsIPConfigType dns_ip_config_type, + gboolean ignore_searches_and_options); #endif /* __NM_L3_CONFIG_DATA_H__ */ diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index fce37071..9dc7bc01 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -5718,6 +5718,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** GError *local = NULL; NMConnectionMultiConnect multi_connect; const char *parent_spec; + gboolean did_realize = FALSE; g_return_val_if_fail(NM_IS_MANAGER(self), FALSE); g_return_val_if_fail(NM_IS_ACTIVE_CONNECTION(active), FALSE); @@ -5892,6 +5893,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** nm_device_get_iface(device)); return FALSE; } + did_realize = TRUE; } } @@ -5923,7 +5925,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** "The controller connection '%s' is not compatible with '%s'", nm_settings_connection_get_id(controller_connection), nm_settings_connection_get_id(sett_conn)); - return FALSE; + goto err_unrealize; } if (!controller_ac) { @@ -5946,7 +5948,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** "Controller connection '%s' can't be activated: ", nm_settings_connection_get_id(controller_connection)); } - return FALSE; + goto err_unrealize; } } @@ -6040,7 +6042,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "Activation failed because the device is unmanaged"); - return FALSE; + goto err_unrealize; } } @@ -6048,6 +6050,11 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** active_connection_add(self, active); nm_device_queue_activation(device, NM_ACT_REQUEST(active)); return TRUE; + +err_unrealize: + if (did_realize) + nm_device_unrealize(device, TRUE, NULL); + return FALSE; } static gboolean diff --git a/src/core/tests/config/global-dns-empty.conf b/src/core/tests/config/global-dns-empty.conf new file mode 100644 index 00000000..fba823bf --- /dev/null +++ b/src/core/tests/config/global-dns-empty.conf @@ -0,0 +1,3 @@ +# Good configuration, an empty global-dns section must be valid + +[global-dns] diff --git a/src/core/tests/config/global-dns-not-set.conf b/src/core/tests/config/global-dns-not-set.conf new file mode 100644 index 00000000..133bd4ed --- /dev/null +++ b/src/core/tests/config/global-dns-not-set.conf @@ -0,0 +1,5 @@ +# Good configuration, an empty [global-dns] must be implicitly assumed because a domain is defined + +[global-dns-domain-*] +servers=4.5.6.7 +options=myoption1 diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index 2980cda7..78fd1057 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -387,7 +387,27 @@ test_config_global_dns(void) g_assert(dns); g_object_unref(config); - /* Check that a file with a domain domain, but without a default one gives a NULL configuration */ + /* Check that a file with an empty global-dns section gives a good configuration. + * Check also that searches and options are not NULL, as this is how we expose to + * D-Bus that global-dns is defined. */ + config = + setup_config(NULL, TEST_DIR "/global-dns-empty.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_assert(nm_global_dns_config_get_searches(dns)); + g_assert(nm_global_dns_config_get_options(dns)); + g_object_unref(config); + + /* Check that a file with a domain, but no global-dns, assumes an implicit empty global-dns */ + config = + setup_config(NULL, TEST_DIR "/global-dns-not-set.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_assert(nm_global_dns_config_get_searches(dns)); + g_assert(nm_global_dns_config_get_options(dns)); + g_object_unref(config); + + /* Check that a file with a 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)); diff --git a/src/libnm-client-impl/tests/test-nm-client.c b/src/libnm-client-impl/tests/test-nm-client.c index 39831509..da252549 100644 --- a/src/libnm-client-impl/tests/test-nm-client.c +++ b/src/libnm-client-impl/tests/test-nm-client.c @@ -1432,13 +1432,13 @@ test_client_wait_shutdown(void) nmtst_assert_success(dbus_connection, error); for (i_run = 0; i_run < N_RUN; i_run++) { - gs_unref_object GCancellable *init_cancellable = g_cancellable_new(); - gs_unref_object NMClient *nmc = NULL; - nm_auto_pop_gmaincontext GMainContext *client_context = NULL; - gboolean b; - gboolean context_integrated = FALSE; - gs_unref_object GCancellable *cancellable_1 = NULL; - GMainContext *ctx; + gs_unref_object GCancellable *init_cancellable = g_cancellable_new(); + gs_unref_object NMClient *nmc = NULL; + nm_auto_pop_and_unref_gmaincontext GMainContext *client_context = NULL; + gboolean b; + gboolean context_integrated = FALSE; + gs_unref_object GCancellable *cancellable_1 = NULL; + GMainContext *ctx; /* Choose a random context for the client. */ ctx = contexts->pdata[nmtst_get_rand_uint32() % contexts->len]; diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c index 668af1f6..614be0f6 100644 --- a/src/libnm-core-impl/nm-setting-wireguard.c +++ b/src/libnm-core-impl/nm-setting-wireguard.c @@ -1477,6 +1477,7 @@ peers_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil) for (i_peer = 0; i_peer < n_peers; i_peer++) { const NMWireGuardPeer *peer = _peers_get(priv, i_peer)->peer; GVariantBuilder builder; + gboolean has_secrets = FALSE; if (!peer->public_key) continue; @@ -1496,11 +1497,13 @@ peers_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil) g_variant_new_string(nm_sock_addr_endpoint_get_endpoint(peer->endpoint))); if (_nm_connection_serialize_secrets(flags, peer->preshared_key_flags) - && peer->preshared_key) + && peer->preshared_key) { g_variant_builder_add(&builder, "{sv}", NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, g_variant_new_string(peer->preshared_key)); + has_secrets = TRUE; + } if (_nm_connection_serialize_non_secret(flags) && peer->preshared_key_flags != NM_SETTING_SECRET_FLAG_NOT_REQUIRED) @@ -1546,6 +1549,20 @@ peers_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil) g_variant_new_strv(strv, peer->allowed_ips->len)); } + if (NM_FLAGS_ANY(flags, + NM_CONNECTION_SERIALIZE_ONLY_SECRETS + | NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED + | NM_CONNECTION_SERIALIZE_WITH_SECRETS_SYSTEM_OWNED + | NM_CONNECTION_SERIALIZE_WITH_SECRETS_NOT_SAVED) + && !_nm_connection_serialize_non_secret(flags)) { + /* The flags indicate that only secrets must be serialized and this + * peer doesn't contain any. Skip the peer. */ + if (!has_secrets) { + g_variant_builder_clear(&builder); + continue; + } + } + if (!any_peers) { g_variant_builder_init(&peers_builder, G_VARIANT_TYPE("aa{sv}")); any_peers = TRUE; diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 2064162a..13d95189 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -5522,6 +5522,223 @@ test_bond_meta(void) /*****************************************************************************/ +static void +check_wg_setting_str(NMSetting *s_wg, + const char *exp_all, + const char *exp_nonsec, + const char *exp_sec) +{ + gs_unref_variant GVariant *dict_all = NULL; + gs_unref_variant GVariant *dict_nonsec = NULL; + gs_unref_variant GVariant *dict_sec = NULL; + gs_free char *str_all = NULL; + gs_free char *str_nonsec = NULL; + gs_free char *str_sec = NULL; + + dict_all = _nm_setting_to_dbus(s_wg, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL); + dict_nonsec = _nm_setting_to_dbus(s_wg, NULL, NM_CONNECTION_SERIALIZE_WITH_NON_SECRET, NULL); + dict_sec = _nm_setting_to_dbus(s_wg, NULL, NM_CONNECTION_SERIALIZE_ONLY_SECRETS, NULL); + + str_all = g_variant_print(dict_all, TRUE); + str_nonsec = g_variant_print(dict_nonsec, TRUE); + str_sec = g_variant_print(dict_sec, TRUE); + + g_assert_cmpstr(exp_all, ==, str_all); + g_assert_cmpstr(exp_nonsec, ==, str_nonsec); + g_assert_cmpstr(exp_sec, ==, str_sec); +} + +static void +test_wireguard_to_dbus(void) +{ + gs_unref_object NMSetting *s_wg = NULL; + nm_auto_unref_wgpeer NMWireGuardPeer *peer1 = NULL; + nm_auto_unref_wgpeer NMWireGuardPeer *peer2 = NULL; + gs_unref_variant GVariant *dict_all = NULL; + gs_unref_variant GVariant *dict_non_secret = NULL; + gs_unref_variant GVariant *dict_only_secrets = NULL; + gs_free char *dict_str = NULL; + const char *test_private_key = "cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM="; + const char *test_public_key1 = "OMhgSum5+NamArI/LTp1mCZQD+CbzZxtOuvDC/RaGWU="; + const char *test_public_key2 = "2S7mA0vEMethVGG0qBm4T5EXbcQ2WYHOuP14Seb7jEM="; + const char *test_preshared_key = "yFGq76ej4lNI0pLLu36L0DgJMxWs4HmH5qNDNOt8AmM="; + + /* Test case 1: Minimal WireGuard setting without peers or private key */ + s_wg = nm_setting_wireguard_new(); + g_object_set(s_wg, + NM_SETTING_WIREGUARD_LISTEN_PORT, + 51820U, + NM_SETTING_WIREGUARD_FWMARK, + 42U, + NULL); + + check_wg_setting_str(s_wg, + /* clang-format off */ + /* all */ + "{'fwmark': <uint32 42>, 'listen-port': <uint32 51820>}", + /* non secrets */ + "{'fwmark': <uint32 42>, 'listen-port': <uint32 51820>}", + /* secrets */ + "@a{sv} {}" + /* clang-format on */ + ); + g_clear_object(&s_wg); + + /* Test case 2: WireGuard setting with private key, no peers */ + s_wg = nm_setting_wireguard_new(); + g_object_set(s_wg, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + test_private_key, + NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_WIREGUARD_LISTEN_PORT, + 51820U, + NM_SETTING_WIREGUARD_FWMARK, + 42U, + NULL); + + check_wg_setting_str(s_wg, + /* clang-format off */ + /* all */ + "{" + "'fwmark': <uint32 42>, " + "'listen-port': <uint32 51820>, " + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>" + "}", + /* non secrets */ + "{" + "'fwmark': <uint32 42>, " + "'listen-port': <uint32 51820>" + "}", + /* secrets */ + "{" + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>" + "}" + /* clang-format on */ + ); + g_clear_object(&s_wg); + + /* Test case 3: WireGuard setting with peers (no PSK) */ + s_wg = nm_setting_wireguard_new(); + g_object_set(s_wg, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + test_private_key, + NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_WIREGUARD_LISTEN_PORT, + 51820U, + NULL); + peer1 = nm_wireguard_peer_new(); + nm_wireguard_peer_set_public_key(peer1, test_public_key1, FALSE); + nm_wireguard_peer_set_endpoint(peer1, "192.168.1.1:51820", FALSE); + nm_wireguard_peer_append_allowed_ip(peer1, "10.0.0.0/8", FALSE); + nm_setting_wireguard_append_peer(NM_SETTING_WIREGUARD(s_wg), peer1); + + check_wg_setting_str(s_wg, + /* clang-format off */ + /* all */ + "{" + "'listen-port': <uint32 51820>, " + "'peers': <[{" + "'public-key': <'OMhgSum5+NamArI/LTp1mCZQD+CbzZxtOuvDC/RaGWU='>, " + "'endpoint': <'192.168.1.1:51820'>, " + "'allowed-ips': <['10.0.0.0/8']>" + "}]>, " + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>" + "}", + /* non secrets */ + "{" + "'listen-port': <uint32 51820>, " + "'peers': <[{" + "'public-key': <'OMhgSum5+NamArI/LTp1mCZQD+CbzZxtOuvDC/RaGWU='>, " + "'endpoint': <'192.168.1.1:51820'>, " + "'allowed-ips': <['10.0.0.0/8']>" + "}]>" + "}", + /* secrets */ + "{" + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>" + "}" + /* clang-format on */ + ); + g_clear_object(&s_wg); + nm_clear_pointer(&peer1, nm_wireguard_peer_unref); + + /* Test case 4: WireGuard setting with peers, one has PSK */ + s_wg = nm_setting_wireguard_new(); + g_object_set(s_wg, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + test_private_key, + NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + NM_SETTING_WIREGUARD_LISTEN_PORT, + 51820U, + NULL); + + /* Peer without PSK */ + peer1 = nm_wireguard_peer_new(); + nm_wireguard_peer_set_public_key(peer1, test_public_key1, FALSE); + nm_wireguard_peer_set_endpoint(peer1, "192.168.1.1:51820", FALSE); + nm_wireguard_peer_append_allowed_ip(peer1, "10.0.0.0/8", FALSE); + nm_setting_wireguard_append_peer(NM_SETTING_WIREGUARD(s_wg), peer1); + + /* Peer with PSK */ + peer2 = nm_wireguard_peer_new(); + nm_wireguard_peer_set_public_key(peer2, test_public_key2, FALSE); + nm_wireguard_peer_set_endpoint(peer2, "192.168.2.1:51820", FALSE); + nm_wireguard_peer_append_allowed_ip(peer2, "172.16.0.0/12", FALSE); + nm_wireguard_peer_set_preshared_key(peer2, test_preshared_key, FALSE); + nm_wireguard_peer_set_preshared_key_flags(peer2, NM_SETTING_SECRET_FLAG_NONE); + nm_setting_wireguard_append_peer(NM_SETTING_WIREGUARD(s_wg), peer2); + + check_wg_setting_str(s_wg, + /* clang-format off */ + /* all */ + "{" + "'listen-port': <uint32 51820>, " + "'peers': <[{" + "'public-key': <'OMhgSum5+NamArI/LTp1mCZQD+CbzZxtOuvDC/RaGWU='>, " + "'endpoint': <'192.168.1.1:51820'>, " + "'allowed-ips': <['10.0.0.0/8']>" + "}, {" + "'public-key': <'2S7mA0vEMethVGG0qBm4T5EXbcQ2WYHOuP14Seb7jEM='>, " + "'endpoint': <'192.168.2.1:51820'>, " + "'preshared-key': <'yFGq76ej4lNI0pLLu36L0DgJMxWs4HmH5qNDNOt8AmM='>, " + "'preshared-key-flags': <uint32 0>, " + "'allowed-ips': <['172.16.0.0/12']>" + "}]>, " + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>" + "}", + /* non secrets */ + "{" + "'listen-port': <uint32 51820>, " + "'peers': <[{" + "'public-key': <'OMhgSum5+NamArI/LTp1mCZQD+CbzZxtOuvDC/RaGWU='>, " + "'endpoint': <'192.168.1.1:51820'>, " + "'allowed-ips': <['10.0.0.0/8']>" + "}, {" + "'public-key': <'2S7mA0vEMethVGG0qBm4T5EXbcQ2WYHOuP14Seb7jEM='>, " + "'endpoint': <'192.168.2.1:51820'>, " + "'preshared-key-flags': <uint32 0>, " + "'allowed-ips': <['172.16.0.0/12']>" + "}]>" + "}", + /* secrets */ + "{" + "'peers': <[{" + "'public-key': <'2S7mA0vEMethVGG0qBm4T5EXbcQ2WYHOuP14Seb7jEM='>, " + "'preshared-key': <'yFGq76ej4lNI0pLLu36L0DgJMxWs4HmH5qNDNOt8AmM='>" + "}]>, " + "'private-key': <'cFoJbK9bSrYrQrjFQGgqsWTO4IUIX0+rsaqNeCw2IWM='>}" + /* clang-format on */ + ); + g_clear_object(&s_wg); + nm_clear_pointer(&peer1, nm_wireguard_peer_unref); + nm_clear_pointer(&peer2, nm_wireguard_peer_unref); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -5649,5 +5866,7 @@ main(int argc, char **argv) g_test_add_func("/libnm/test_bond_meta", test_bond_meta); + g_test_add_func("/libnm/test_wireguard_to_dbus", test_wireguard_to_dbus); + return g_test_run(); } diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index ba5380af..fdd7283e 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -1350,6 +1350,67 @@ reader_parse_ethtool(Reader *reader, char *argument) } static void +reader_parse_dhcp_client_id(Reader *reader, char *argument) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip4; + const char *interface; + gs_free char *client_id = NULL; + gs_free guint8 *buf = NULL; + gsize len = 0; + + interface = get_word(&argument, ':'); + if (!interface) { + _LOGW(LOGD_CORE, "rd.net.dhcp.client-id: missing interface"); + return; + } + + if (!argument || !*argument) { + _LOGW(LOGD_CORE, "rd.net.dhcp.client-id: missing client-id"); + return; + } + + if (argument[0] == '@') { + /* The client-id is a plain string but we still encode it as + * hex string. Otherwise, we could pass the string as-is, but we + * would need to handle special keywords like "mac", "perm-mac", etc. + */ + if (argument[1] != '\0') { + len = strlen(argument); + buf = (guint8 *) nm_memdup(argument, len + 1); + buf[0] = '\0'; + } + } else { + /* Try to parse it as hex string */ + buf = nm_utils_hexstr2bin_alloc(argument, FALSE, FALSE, "-", 0, &len); + } + + if (buf) { + client_id = nm_utils_bin2hexstr_full(buf, len, ':', FALSE, NULL); + } + + if (!client_id) { + _LOGW(LOGD_CORE, + "rd.net.dhcp.client-id: invalid client-id \"%s\". Must be hexadecimal bytes " + "separated by dashes (for example \"00-01-02-03-04-05-06\"), or '@' followed by a " + "string", + argument); + return; + } + + if (len < 2) { + _LOGW(LOGD_CORE, + "rd.net.dhcp.client-id: invalid client-id \"%s\". Must be at least two bytes", + argument); + return; + } + + connection = reader_get_connection(reader, interface, NULL, TRUE); + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_object_set(s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, client_id, NULL); +} + +static void _normalize_conn(gpointer key, gpointer value, gpointer user_data) { NMConnection *connection = value; @@ -1365,6 +1426,8 @@ _normalize_conn(gpointer key, gpointer value, gpointer user_data) NULL, NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, NULL, + NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, + NULL, NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NULL, NM_SETTING_IP_CONFIG_DHCP_DSCP, @@ -1583,6 +1646,8 @@ nmi_cmdline_reader_parse(const char *etc_connections_dir, g_ptr_array_add(znets, g_strdup(argument)); } else if (nm_streq(tag, "rd.znet_ifname")) { reader_parse_znet_ifname(reader, argument); + } else if (nm_streq(tag, "rd.net.dhcp.client-id")) { + reader_parse_dhcp_client_id(reader, argument); } else if (g_ascii_strcasecmp(tag, "BOOTIF") == 0) { nm_clear_g_free(&bootif_val); bootif_val = g_strdup(argument); diff --git a/src/nm-initrd-generator/nmi-nbft-reader.c b/src/nm-initrd-generator/nmi-nbft-reader.c index 5d12086f..dfab0390 100644 --- a/src/nm-initrd-generator/nmi-nbft-reader.c +++ b/src/nm-initrd-generator/nmi-nbft-reader.c @@ -94,6 +94,33 @@ find_conn_for_wired_mac(GPtrArray *a, const char *hwaddr) return NULL; } +static gboolean +hfi_is_dhcp(struct nbft_info_hfi *hfi, int family) +{ + /* There are several flags that may indicate the HFI is set for DHCP + * per NVM Express® Boot Specification, Revision 1.3. As the HFI + * Transport Flags (HFITFLAGS) are not publicly exposed by the libnvme + * API, only the DHCP Override (DHCPO) flag and the IP Origin (IPORIG) + * value is available. + * + * The bit 03 of the HFI Transport Flags (HFITFLAGS) is about an advanced + * stateless mechanism - IPv6-SLAAC and IPv6-ND, stating that "the DHCP + * Override bit shall be cleared to 0, and the IP Origin field shall + * be cleared to 0". This nm-initrd-generator will ignore this flag, + * expecting an IP address to be provided by the usual HFI fields + * just like in a static adressing case. + * + * DHCP Override (DHCPO): "The HFI information was populated by + * consuming the DHCP on this interface." + * + * IP Origin (IPORIG): "If set to 3h (IpPrefixOriginDhcp), then the + * IP Address was acquired through DHCP, and the IP Address specified + * in this HFI should not be reused by the OS." + */ + return hfi->tcp_info.dhcp_override || hfi->tcp_info.ip_origin == 3 /* IpPrefixOriginDhcp */ + || is_valid_addr(family, hfi->tcp_info.dhcp_server_ipaddr); +} + static NMConnection * create_wired_conn(struct nbft_info_hfi *hfi, const char *conn_name, @@ -183,6 +210,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char return; } g_ptr_array_add(a, parent_connection); + nm_clear_g_free(&conn_name); } conn_name = format_conn_name(table_name, hfi, TRUE); @@ -208,7 +236,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, NULL); - if (is_valid_addr(AF_INET, hfi->tcp_info.dhcp_server_ipaddr)) { + if (hfi_is_dhcp(hfi, family)) { g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, @@ -260,7 +288,7 @@ parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); - if (is_valid_addr(AF_INET6, hfi->tcp_info.dhcp_server_ipaddr)) { + if (hfi_is_dhcp(hfi, family)) { g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, diff --git a/src/nm-initrd-generator/tests/meson.build b/src/nm-initrd-generator/tests/meson.build index 8fa3bcac..897a2148 100644 --- a/src/nm-initrd-generator/tests/meson.build +++ b/src/nm-initrd-generator/tests/meson.build @@ -6,6 +6,10 @@ test_units = [ 'test-cmdline-reader', ] +if enable_nbft + test_units += [ 'test-nbft-reader' ] +endif + foreach test_unit : test_units exe = executable( test_unit, diff --git a/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 b/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 new file mode 100644 index 00000000..2dea9363 --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-Dell.PowerEdge.R760 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-dhcp-ipv4 b/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-dhcp-ipv4 new file mode 100644 index 00000000..1af159de --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-dhcp/firmware/acpi/tables/NBFT-dhcp-ipv4 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery new file mode 100644 index 00000000..0fbb35cf --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi new file mode 100644 index 00000000..c34875bc --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-multi Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc new file mode 100644 index 00000000..5d0a6cc0 --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-rhpoc Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 new file mode 100644 index 00000000..bf3f8404 --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv4-static/firmware/acpi/tables/NBFT-static-ipv4 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 new file mode 100644 index 00000000..64457d7d --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-auto-ipv6 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 new file mode 100644 index 00000000..20715eeb --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-dhcp-ipv6 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc new file mode 100644 index 00000000..7a0690cb --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv6-auto/firmware/acpi/tables/NBFT-ipv6-noip+disc Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 b/src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 new file mode 100644 index 00000000..07b09cfb --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-ipv6-static/firmware/acpi/tables/NBFT-static-ipv6 Binary files differdiff --git a/src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete b/src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete new file mode 100644 index 00000000..da385318 --- /dev/null +++ b/src/nm-initrd-generator/tests/nbft-vlan/firmware/acpi/tables/NBFT-qemu-vlans-incomplete Binary files differdiff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c index cd7b1069..ac722872 100644 --- a/src/nm-initrd-generator/tests/test-cmdline-reader.c +++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c @@ -2786,6 +2786,149 @@ test_plain_equal_char(void) /*****************************************************************************/ +#define _dhcp_client_id_check_invalid(arg) \ + G_STMT_START \ + { \ + gs_unref_hashtable GHashTable *_connections2 = NULL; \ + \ + _connections2 = _parse_cons(NM_MAKE_STRV(arg)); \ + g_test_assert_expected_messages(); \ + g_assert_cmpint(g_hash_table_size(_connections2), ==, 0); \ + } \ + G_STMT_END + +#define _dhcp_client_id_check_v(strv, exp_ifname, exp_client_id) \ + G_STMT_START \ + { \ + gs_unref_object NMConnection *_connection = NULL; \ + NMSettingIPConfig *_s_ip4; \ + \ + _connection = _parse_con(strv, exp_ifname); \ + \ + g_test_assert_expected_messages(); \ + \ + g_assert(nm_connection_get_setting_connection(_connection)); \ + g_assert(nm_connection_is_type(_connection, NM_SETTING_WIRED_SETTING_NAME)); \ + g_assert(nm_connection_get_setting_ip4_config(_connection)); \ + g_assert(nm_connection_get_setting_ip6_config(_connection)); \ + _s_ip4 = nm_connection_get_setting_ip4_config(_connection); \ + g_assert(NM_IS_SETTING_IP_CONFIG(_s_ip4)); \ + \ + g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_client_id(NM_SETTING_IP4_CONFIG(_s_ip4)), \ + ==, \ + (exp_client_id)); \ + } \ + G_STMT_END + +#define _dhcp_client_id_check(arg, exp_ifname, exp_client_id) \ + _dhcp_client_id_check_v(NM_MAKE_STRV("" arg ""), (exp_ifname), (exp_client_id)) + +#define DHCP_CLIENT_ID_INVALID_MSG(_id) \ + "cmdline-reader: " \ + "rd.net.dhcp.client-id: invalid client-id \"" _id "\". Must be hexadecimal bytes " \ + "separated by dashes (for example \"00-01-02-03-04-05-06\"), or '@' followed by a string" + +static void +test_rd_dhcp_client_id(void) +{ + NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dhcp.client-id: missing interface"); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id="); + + NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dhcp.client-id: missing interface"); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=:"); + + NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dhcp.client-id: missing client-id"); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=eth0:"); + + NMTST_EXPECT_NM_WARN(DHCP_CLIENT_ID_INVALID_MSG("invalid")); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=eth0:invalid"); + + NMTST_EXPECT_NM_WARN(DHCP_CLIENT_ID_INVALID_MSG("01:AA:BB:CC:DD:EE:FF")); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=eth0:01:AA:BB:CC:DD:EE:FF"); + + NMTST_EXPECT_NM_WARN(DHCP_CLIENT_ID_INVALID_MSG("@")); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=eth0:@"); + + NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dhcp.client-id: invalid client-id \"01\". Must be " + "at least two bytes"); + _dhcp_client_id_check_invalid("rd.net.dhcp.client-id=eth0:01"); + + /* Client-id with hex string */ + _dhcp_client_id_check("rd.net.dhcp.client-id=eth0:01-aa-BB-cc-dd-EE-ff", + "eth0", + "01:aa:bb:cc:dd:ee:ff"); + + /* Client-id with plain string */ + _dhcp_client_id_check("rd.net.dhcp.client-id=eth0:@test.com", + "eth0", + "00:74:65:73:74:2e:63:6f:6d"); + + /* Minimal client-id, hex */ + _dhcp_client_id_check("rd.net.dhcp.client-id=eth1:01-02", "eth1", "01:02"); + + /* Minimal client-id, string */ + _dhcp_client_id_check("rd.net.dhcp.client-id=eth1:@1", "eth1", "00:31"); + + /* Long client-id */ + _dhcp_client_id_check( + "rd.net.dhcp.client-id=enp1s0:" + "01-02-03-04-05-06-07-08-09-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-" + "25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-" + "49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72", + "enp1s0", + "01:02:03:04:05:06:07:08:09:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:" + "25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:" + "49:50:51:52:53:54:55:56:57:58:59:60:61:62:63:64:65:66:67:68:69:70:71:72"); + + /* Test ordering: client-id before ip= */ + _dhcp_client_id_check_v( + NM_MAKE_STRV("rd.net.dhcp.client-id=eth0:aa-bb-cc-dd-ee-ff", "ip=eth0:dhcp"), + "eth0", + "aa:bb:cc:dd:ee:ff"); + + /* Test ordering: client-id after ip= */ + _dhcp_client_id_check_v( + NM_MAKE_STRV("ip=eth2:dhcp", "rd.net.dhcp.client-id=eth2:ba-da-cc-dd-ee-ff"), + "eth2", + "ba:da:cc:dd:ee:ff"); + + /* Duplicate option: last wins */ + _dhcp_client_id_check_v(NM_MAKE_STRV("ip=eth3:dhcp", + "rd.net.dhcp.client-id=eth3:01-02", + "rd.net.dhcp.client-id=eth3:01-03"), + "eth3", + "01:03"); + + /* Multiple connections */ + { + gs_unref_hashtable GHashTable *connections = NULL; + NMConnection *connection; + NMSettingIP4Config *s_ip4; + + connections = _parse_cons(NM_MAKE_STRV("ip=eth0:dhcp", + "ip=eth1:dhcp", + "rd.net.dhcp.client-id=eth1:01-01-01", + "rd.net.dhcp.client-id=eth0:00-00-00")); + + g_assert_nonnull(connections); + g_assert_cmpint(g_hash_table_size(connections), ==, 2); + + connection = g_hash_table_lookup(connections, "eth0"); + g_assert_nonnull(connection); + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting_ip4_config(connection); + g_assert_nonnull(s_ip4); + g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_client_id(s_ip4), ==, "00:00:00"); + + connection = g_hash_table_lookup(connections, "eth1"); + g_assert_nonnull(connection); + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting_ip4_config(connection); + g_assert_nonnull(s_ip4); + g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_client_id(s_ip4), ==, "01:01:01"); + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -2848,6 +2991,7 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/rd_ethtool", test_rd_ethtool); g_test_add_func("/initrd/cmdline/plain_equal_char", test_plain_equal_char); g_test_add_func("/initrd/cmdline/global_dns", test_global_dns); + g_test_add_func("/initrd/cmdline/rd_dhcp_client_id", test_rd_dhcp_client_id); return g_test_run(); } diff --git a/src/nm-initrd-generator/tests/test-nbft-reader.c b/src/nm-initrd-generator/tests/test-nbft-reader.c new file mode 100644 index 00000000..f93d3d76 --- /dev/null +++ b/src/nm-initrd-generator/tests/test-nbft-reader.c @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-test-utils.h" + +#include "nm-initrd-generator/nm-initrd-generator.h" + +#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/nm-initrd-generator/tests" + +/*****************************************************************************/ + +static NMConnection * +find_connection_for_mac(NMConnection **nbft_connections, const char *expected_mac, guint32 vlan_id) +{ + NMConnection **c; + NMSettingWired *s_wired; + NMSettingVlan *s_vlan; + const char *mac_address; + + for (c = nbft_connections; c && *c; c++) { + s_wired = nm_connection_get_setting_wired(*c); + g_assert(s_wired); + mac_address = nm_setting_wired_get_mac_address(s_wired); + g_assert(mac_address); + if (!nm_utils_hwaddr_matches(mac_address, -1, expected_mac, -1)) + continue; + s_vlan = nm_connection_get_setting_vlan(*c); + if (vlan_id > 0) { + if (!s_vlan) + continue; + if (nm_setting_vlan_get_id(s_vlan) != vlan_id) + continue; + } else if (s_vlan) + continue; + return *c; + } + + return NULL; +} + +static void +verify_connection(NMConnection *c, const char *expected_mac, guint32 expected_vlan_id) +{ + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingVlan *s_vlan; + const char *mac_address; + + nmtst_assert_connection_verifies_without_normalization(c); + + s_con = nm_connection_get_setting_connection(c); + g_assert(s_con); + + g_assert(g_str_has_prefix(nm_setting_connection_get_id(s_con), "NBFT")); + g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); + g_assert(nm_setting_connection_get_autoconnect_priority(s_con) + == NMI_AUTOCONNECT_PRIORITY_FIRMWARE); + + s_wired = nm_connection_get_setting_wired(c); + g_assert(s_wired); + mac_address = nm_setting_wired_get_mac_address(s_wired); + g_assert(mac_address); + g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac, -1)); + + if (expected_vlan_id > 0) { + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_VLAN_SETTING_NAME); + s_vlan = nm_connection_get_setting_vlan(c); + g_assert(s_vlan); + g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, expected_vlan_id); + g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, NULL); + } else { + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_WIRED_SETTING_NAME); + } +} + +static void +verify_ipv4(NMConnection *c, const char *addr, int mask, const char *gateway) +{ + NMSettingIPConfig *s_ip4; + NMIPAddress *ip4_addr; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + + g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); + + g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); + 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), ==, addr); + g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, mask); + + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, gateway); +} + +static void +verify_ipv4_dhcp(NMConnection *c) +{ + NMSettingIPConfig *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); +} + +static void +verify_ipv4_disabled(NMConnection *c) +{ + NMSettingIPConfig *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config(c); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED); +} + +static void +verify_ipv6(NMConnection *c, const char *addr, int prefix, const char *gateway) +{ + NMSettingIPConfig *s_ip6; + NMIPAddress *ip6_addr; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL); + + g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); + + g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1); + ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0); + g_assert(ip6_addr); + g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, addr); + g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, prefix); + + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, gateway); +} + +static void +verify_ipv6_auto(NMConnection *c) +{ + NMSettingIPConfig *s_ip6; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); +} + +static void +verify_ipv6_disabled(NMConnection *c) +{ + NMSettingIPConfig *s_ip6; + + s_ip6 = nm_connection_get_setting_ip6_config(c); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED); +} + +static int +count_nm_conn(NMConnection **connections) +{ + int cnt; + + for (cnt = 0; connections && *connections; connections++, cnt++) + ; + + return cnt; +} + +static void +free_connections(NMConnection **connections) +{ + NMConnection **c; + + for (c = connections; c && *c; c++) + g_object_unref(*c); + g_free(connections); +} + +static void +test_read_nbft_ipv4_static(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv4-static", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 6); + + /* NBFT-multi HFI 1 */ + expected_mac_address = "52:54:00:72:c5:ae"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.122.158", 24, "192.168.122.1"); + verify_ipv6_disabled(connection); + + /* NBFT-multi HFI 2 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery HFI 1 */ + expected_mac_address = "00:62:0b:cb:eb:70"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "172.18.240.1", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R660-fw1.5.5-mpath+discovery HFI 2 */ + expected_mac_address = "00:62:0b:cb:eb:71"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "172.18.230.2", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-rhpoc */ + expected_mac_address = "ea:eb:d3:58:89:58"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.101.30", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-static-ipv4 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.49.50", 24, NULL); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv4_dhcp(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv4-dhcp", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 2); + + /* NBFT-dhcp-ipv4 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + /* NBFT-Dell.PowerEdge.R760 */ + expected_mac_address = "b0:26:28:e8:7c:0e"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_dhcp(connection); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv6_static(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv6-static", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 1); + + /* NBFT-static-ipv6 */ + expected_mac_address = "52:54:00:9e:20:1a"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6(connection, "fd09:9a46:b5c1:1fe::10", 64, NULL); + verify_ipv4_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_ipv6_auto(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-ipv6-auto", &hostname); + g_assert_nonnull(hostname); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 3); + + /* NBFT-auto-ipv6 */ + expected_mac_address = "52:54:00:9e:20:1a"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6(connection, "fd09:9a46:b5c1:1ff:5054:ff:fe9e:201a", 64, NULL); + verify_ipv4_disabled(connection); + + /* NBFT-dhcp-ipv6 */ + expected_mac_address = "52:54:00:b8:19:b9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6_auto(connection); + verify_ipv4_disabled(connection); + + /* NBFT-ipv6-noip+disc */ + expected_mac_address = "40:a6:b7:c0:8a:c9"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv6_auto(connection); + verify_ipv4_disabled(connection); + + free_connections(nbft_connections); +} + +static void +test_read_nbft_vlan(void) +{ + NMConnection **nbft_connections; + NMConnection *connection; + const char *expected_mac_address; + gs_free char *hostname = NULL; + + nbft_connections = nmi_nbft_reader_parse(TEST_INITRD_DIR "/nbft-vlan", &hostname); + g_assert_cmpstr(hostname, ==, NULL); + g_assert_cmpint(count_nm_conn(nbft_connections), ==, 4); + + /* NBFT-qemu-vlans-incomplete HFI 1 */ + expected_mac_address = "52:54:00:72:c5:ae"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4(connection, "192.168.122.158", 24, "192.168.122.1"); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 0); + verify_connection(connection, expected_mac_address, 0); + verify_ipv4_disabled(connection); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 VLAN 11 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 11); + verify_connection(connection, expected_mac_address, 11); + verify_ipv4(connection, "192.168.124.58", 24, NULL); + verify_ipv6_disabled(connection); + + /* NBFT-qemu-vlans-incomplete HFI 2 VLAN 12 */ + expected_mac_address = "52:54:00:72:c5:af"; + connection = find_connection_for_mac(nbft_connections, expected_mac_address, 12); + verify_connection(connection, expected_mac_address, 12); + verify_ipv4(connection, "192.168.125.58", 24, NULL); + verify_ipv6_disabled(connection); + + free_connections(nbft_connections); +} + +NMTST_DEFINE(); + +int +main(int argc, char **argv) +{ + nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func("/initrd/nbft/ipv4-static", test_read_nbft_ipv4_static); + g_test_add_func("/initrd/nbft/ipv4-dhcp", test_read_nbft_ipv4_dhcp); + g_test_add_func("/initrd/nbft/ipv6-static", test_read_nbft_ipv6_static); + g_test_add_func("/initrd/nbft/ipv6-auto", test_read_nbft_ipv6_auto); + g_test_add_func("/initrd/nbft/vlan", test_read_nbft_vlan); + + return g_test_run(); +} diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index cc76d37b..80080056 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -2247,9 +2247,9 @@ class TestNmcli(unittest.TestCase): extra_env=no_dbus_env, replace_stderr=[ Util.ReplaceTextRegex( - # depending on glib version, it prints `%s', '%s', or “%s”. - # depending on libc version, it converts unicode to ? or *. - r"Key/Value pair 0, [`*?']invalid[*?'], in address element [`*?']very:invalid[*?'] does not contain an equal sign", + # Depending on glib version, it prints `%s', '%s', or “%s”. + # Some libc versions convert the multi-byte UTF-8 sequence to ? or *. + r"Key/Value pair 0, .*invalid.*, in address element .*very:invalid.* does not contain an equal sign", "Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign", ) ], |