From f2eb3dea659d66437d6564abef49fe4eb8964a38 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 Aug 2009 17:15:03 -0400 Subject: [PATCH 1/4] core: base infrastructure for connection assumption Figure out what connections can be assumed when a device is added, and on shutdown don't blow away connections that can be assumed on NM restart. --- src/dhcp-manager/nm-dhcp-dhclient.c | 204 ++++++++++++++++++++++++++++ src/dhcp-manager/nm-dhcp-dhcpcd.c | 5 + src/dhcp-manager/nm-dhcp-manager.c | 13 ++ src/dhcp-manager/nm-dhcp-manager.h | 7 + src/nm-device-ethernet.c | 196 +++++++++++++++++++++++++- src/nm-device-interface.c | 21 +++ src/nm-device-interface.h | 7 + src/nm-device.c | 57 ++++++-- src/nm-device.h | 2 + src/nm-manager.c | 43 ++++-- 10 files changed, 532 insertions(+), 23 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index f35465976b..ac7d9f58ab 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -18,6 +18,10 @@ * Copyright (C) 2005 - 2008 Red Hat, Inc. */ +#define _XOPEN_SOURCE +#include +#undef _XOPEN_SOURCE + #include #include #include @@ -74,6 +78,206 @@ get_leasefile_for_iface (const char * iface, const char *uuid) NM_DHCP_MANAGER_LEASE_FILE_EXT); } +static void +add_lease_option (GHashTable *hash, char *line) +{ + char *spc; + + spc = strchr (line, ' '); + if (!spc) { + g_warning ("%s: line '%s' did not contain a space", __func__, line); + return; + } + + /* If it's an 'option' line, split at second space */ + if (g_str_has_prefix (line, "option ")) { + spc = strchr (spc + 1, ' '); + if (!spc) { + g_warning ("%s: option line '%s' did not contain a second space", + __func__, line); + return; + } + } + + /* Split the line at the space */ + *spc = '\0'; + spc++; + + /* Kill the ';' at the end of the line, if any */ + if (*(spc + strlen (spc) - 1) == ';') + *(spc + strlen (spc) - 1) = '\0'; + + /* Treat 'interface' specially */ + if (g_str_has_prefix (line, "interface")) { + if (*(spc) == '"') + spc++; /* Jump past the " */ + if (*(spc + strlen (spc) - 1) == '"') + *(spc + strlen (spc) - 1) = '\0'; /* Kill trailing " */ + } + + g_hash_table_insert (hash, g_strdup (line), g_strdup (spc)); +} + +GSList * +nm_dhcp_client_get_lease_ip4_config (const char *iface, const char *uuid) +{ + GSList *parsed = NULL, *iter, *leases = NULL; + char *contents = NULL; + char *leasefile; + char **line, **split = NULL; + GHashTable *hash = NULL; + + leasefile = get_leasefile_for_iface (iface, uuid); + if (!leasefile) + return NULL; + + if (!g_file_test (leasefile, G_FILE_TEST_EXISTS)) + goto out; + + if (!g_file_get_contents (leasefile, &contents, NULL, NULL)) + goto out; + + split = g_strsplit_set (contents, "\n\r", -1); + g_free (contents); + if (!split) + goto out; + + for (line = split; line && *line; line++) { + *line = g_strstrip (*line); + + if (!strcmp (*line, "}")) { + /* Lease ends */ + parsed = g_slist_append (parsed, hash); + hash = NULL; + } else if (!strcmp (*line, "lease {")) { + /* Beginning of a new lease */ + if (hash) { + g_warning ("%s: lease file %s malformed; new lease started " + "without ending previous lease", + __func__, leasefile); + g_hash_table_destroy (hash); + } + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + } else if (strlen (*line)) + add_lease_option (hash, *line); + } + g_strfreev (split); + + /* Check if the last lease in the file was properly ended */ + if (hash) { + g_warning ("%s: lease file %s malformed; new lease started " + "without ending previous lease", + __func__, leasefile); + g_hash_table_destroy (hash); + hash = NULL; + } + + for (iter = parsed; iter; iter = g_slist_next (iter)) { + NMIP4Config *ip4; + NMIP4Address *addr; + const char *data; + struct in_addr tmp; + guint32 prefix; + struct tm expire; + + hash = iter->data; + + /* Make sure this lease is for the interface we want */ + data = g_hash_table_lookup (hash, "interface"); + if (!data || strcmp (data, iface)) + continue; + + data = g_hash_table_lookup (hash, "expire"); + if (data) { + time_t now_tt; + struct tm *now; + + /* Read lease expiration (in UTC) */ + if (!strptime (data, "%w %Y/%m/%d %H:%M:%S", &expire)) { + g_warning ("%s: couldn't parse expire time '%s'", + __func__, data); + continue; + } + + now_tt = time (NULL); + now = gmtime(&now_tt); + + /* Ignore this lease if it's already expired */ + if (expire.tm_year < now->tm_year) + continue; + else if (expire.tm_year == now->tm_year) { + if (expire.tm_mon < now->tm_mon) + continue; + else if (expire.tm_mon == now->tm_mon) { + if (expire.tm_mday < now->tm_mday) + continue; + else if (expire.tm_mday == now->tm_mday) { + if (expire.tm_hour < now->tm_hour) + continue; + else if (expire.tm_hour == now->tm_hour) { + if (expire.tm_min < now->tm_min) + continue; + else if (expire.tm_min == now->tm_min) { + if (expire.tm_sec <= now->tm_sec) + continue; + } + } + } + } + } + /* If we get this far, the lease hasn't expired */ + } + + data = g_hash_table_lookup (hash, "fixed-address"); + if (!data) + continue; + + ip4 = nm_ip4_config_new (); + addr = nm_ip4_address_new (); + + /* IP4 address */ + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 address '%s'", __func__, data); + goto error; + } + nm_ip4_address_set_address (addr, tmp.s_addr); + + /* Netmask */ + data = g_hash_table_lookup (hash, "option subnet-mask"); + if (!data) + data = "255.255.255.0"; /* FIXME: assume class C? */ + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 subnet mask '%s'", __func__, data); + goto error; + } + prefix = nm_utils_ip4_netmask_to_prefix (tmp.s_addr); + nm_ip4_address_set_prefix (addr, prefix); + + /* Gateway */ + data = g_hash_table_lookup (hash, "option routers"); + if (data) { + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 gateway '%s'", __func__, data); + goto error; + } + nm_ip4_address_set_gateway (addr, tmp.s_addr); + } + + nm_ip4_config_take_address (ip4, addr); + leases = g_slist_append (leases, ip4); + continue; + + error: + nm_ip4_address_unref (addr); + g_object_unref (ip4); + } + +out: + g_slist_foreach (parsed, (GFunc) g_hash_table_destroy, NULL); + g_free (leasefile); + return leases; +} #define DHCP_CLIENT_ID_TAG "send dhcp-client-identifier" diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index a6ce8d21e6..a8d929a528 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -49,6 +49,11 @@ get_pidfile_for_iface (const char * iface) NM_DHCP_MANAGER_PID_FILE_EXT); } +GSList * +nm_dhcp_client_get_lease_ip4_config (const char *iface, const char *uuid) +{ + return NULL; +} static void dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED) diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index bdd2695b2a..f099ea289c 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -1121,3 +1121,16 @@ nm_dhcp_manager_set_hostname_provider (NMDHCPManager *manager, g_object_weak_ref (G_OBJECT (provider), hostname_provider_destroyed, manager); } } + +GSList * +nm_dhcp_manager_get_lease_ip4_config (NMDHCPManager *self, + const char *iface, + const char *uuid) +{ + g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (uuid != NULL, NULL); + + return nm_dhcp_client_get_lease_ip4_config (iface, uuid); +} + diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index 6880a2336c..124008493a 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -107,6 +107,10 @@ gboolean nm_dhcp_manager_foreach_dhcp4_option (NMDHCPManager *self, GHFunc func, gpointer user_data); +GSList * nm_dhcp_manager_get_lease_ip4_config (NMDHCPManager *self, + const char *iface, + const char *uuid); + /* The following are implemented by the DHCP client backends */ GPid nm_dhcp_client_start (NMDHCPDevice *device, const char *uuid, @@ -118,6 +122,9 @@ gboolean nm_dhcp_client_process_classless_routes (GHashTable *options, NMIP4Config *ip4_config, guint32 *gwaddr); +GSList * nm_dhcp_client_get_lease_ip4_config (const char *iface, + const char *uuid); + /* Test functions */ NMIP4Config *nm_dhcp_manager_options_to_ip4_config (const char *iface, GHashTable *options); diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 759a183ea9..2c68f790d1 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -53,6 +53,7 @@ #include "ppp-manager/nm-ppp-manager.h" #include "nm-utils.h" #include "nm-properties-changed-signal.h" +#include "nm-dhcp-manager.h" #include "nm-device-ethernet-glue.h" @@ -280,8 +281,8 @@ constructor (GType type, guint32 caps; object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type, - n_construct_params, - construct_params); + n_construct_params, + construct_params); if (!object) return NULL; @@ -1472,6 +1473,196 @@ spec_match_list (NMDevice *device, const GSList *specs) return matched; } +static gboolean +wired_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingWired *s_wired; + struct ether_addr ether; + const GByteArray *s_ether; + + s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + if (!s_wired) + return FALSE; + + /* MAC address check */ + s_ether = nm_setting_wired_get_mac_address (s_wired); + if (s_ether) { + nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (self), ðer); + + if (memcmp (s_ether->data, ether.ether_addr_octet, ETH_ALEN)) + return FALSE; + } + + return TRUE; +} + +typedef struct { + int ifindex; + NMIP4Address *addr; + gboolean found; +} AddrData; + +static void +check_one_address (struct nl_object *object, void *user_data) +{ + AddrData *data = user_data; + struct rtnl_addr *addr = (struct rtnl_addr *) object; + struct nl_addr *local; + struct in_addr tmp; + + if (rtnl_addr_get_ifindex (addr) != data->ifindex) + return; + if (rtnl_addr_get_family (addr) != AF_INET) + return; + + if (nm_ip4_address_get_prefix (data->addr) != rtnl_addr_get_prefixlen (addr)) + return; + + local = rtnl_addr_get_local (addr); + if (nl_addr_get_family (local) != AF_INET) + return; + if (nl_addr_get_len (local) != sizeof (struct in_addr)) + return; + if (!nl_addr_get_binary_addr (local)) + return; + + memcpy (&tmp, nl_addr_get_binary_addr (local), nl_addr_get_len (local)); + if (tmp.s_addr != nm_ip4_address_get_address (data->addr)) + return; + + /* Yay, found it */ + data->found = TRUE; +} + +static gboolean +ip4_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingIP4Config *s_ip4; + NMSettingConnection *s_con; + struct nl_handle *nlh = NULL; + struct nl_cache *addr_cache = NULL; + int i, num; + GSList *leases, *iter; + NMDHCPManager *dhcp_mgr; + const char *method; + int ifindex; + AddrData check_data; + + ifindex = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (self)); + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + g_assert (nm_setting_connection_get_uuid (s_con)); + + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (!s_ip4) + return FALSE; + + /* Read all the device's IP addresses */ + nlh = nm_netlink_get_default_handle (); + if (!nlh) + return FALSE; + + addr_cache = rtnl_addr_alloc_cache (nlh); + if (!addr_cache) + return FALSE; + nl_cache_mngt_provide (addr_cache); + + /* Get any saved leases that apply to this connection */ + dhcp_mgr = nm_dhcp_manager_get (); + leases = nm_dhcp_manager_get_lease_ip4_config (dhcp_mgr, + nm_device_get_iface (self), + nm_setting_connection_get_uuid (s_con)); + g_object_unref (dhcp_mgr); + + method = nm_setting_ip4_config_get_method (s_ip4); + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + gboolean found = FALSE; + + /* Find at least one lease's address on the device */ + for (iter = leases; iter; iter = g_slist_next (iter)) { + NMIP4Config *addr = iter->data; + + memset (&check_data, 0, sizeof (check_data)); + check_data.ifindex = ifindex; + check_data.found = FALSE; + check_data.addr = nm_ip4_config_get_address (addr, 0); + + nl_cache_foreach (addr_cache, check_one_address, &check_data); + if (check_data.found) { + found = TRUE; /* Yay, device has same address as a lease */ + break; + } + } + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + return found; + } else { + /* Maybe the connection used to be DHCP and there are stale leases; ignore them */ + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + } + + /* 'shared' and 'link-local' aren't supported methods because 'shared' + * requires too much iptables and dnsmasq state to be reclaimed, and + * avahi-autoipd isn't smart enough to allow the link-local address to be + * determined at any point other than when it was first assigned. + */ + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + return FALSE; + + /* Everything below for static addressing */ + + /* Find all IP4 addresses of this connection in the device's address list */ + num = nm_setting_ip4_config_get_num_addresses (s_ip4); + for (i = 0; i < num; i++) { + memset (&check_data, 0, sizeof (check_data)); + check_data.ifindex = ifindex; + check_data.found = FALSE; + check_data.addr = nm_setting_ip4_config_get_address (s_ip4, i); + + nl_cache_foreach (addr_cache, check_one_address, &check_data); + if (!check_data.found) + return FALSE; + } + + /* Success; all the connection's static IP addresses are assigned to the device */ + return TRUE; +} + +static NMConnection * +connection_match_config (NMDevice *self, const GSList *connections) +{ + GSList *iter; + NMSettingConnection *s_con; + + for (iter = (GSList *) connections; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRED_SETTING_NAME)) + continue; + + /* Can't assume 802.1x or PPPoE connections; they have too much state + * that's impossible to get on-the-fly from PPPoE or the supplicant. + */ + if ( nm_connection_get_setting (candidate, NM_TYPE_SETTING_802_1X) + || nm_connection_get_setting (candidate, NM_TYPE_SETTING_PPPOE)) + continue; + + if (!wired_match_config (self, candidate)) + continue; + + if (!ip4_match_config (self, candidate)) + continue; + + return candidate; + } + + return NULL; +} + static void dispose (GObject *object) { @@ -1587,6 +1778,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->spec_match_list = spec_match_list; + parent_class->connection_match_config = connection_match_config; /* properties */ g_object_class_install_property diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 5647adb425..7f287a8696 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -282,8 +282,29 @@ gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device, const GSList *specs) { + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE); + if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list) return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list (device, specs); return FALSE; } +NMConnection * +nm_device_interface_connection_match_config (NMDeviceInterface *device, + const GSList *connections) +{ + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), NULL); + + if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config) + return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config (device, connections); + return NULL; +} + +gboolean +nm_device_interface_can_assume_connection (NMDeviceInterface *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE); + + return !!NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config; +} + diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 760cccacc7..97a95da479 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -88,6 +88,8 @@ struct _NMDeviceInterface { gboolean (*spec_match_list) (NMDeviceInterface *device, const GSList *specs); + NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs); + /* Signals */ void (*state_changed) (NMDeviceInterface *device, NMDeviceState new_state, @@ -115,4 +117,9 @@ NMDeviceState nm_device_interface_get_state (NMDeviceInterface *device); gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device, const GSList *specs); +NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device, + const GSList *connections); + +gboolean nm_device_interface_can_assume_connection (NMDeviceInterface *device); + #endif /* NM_DEVICE_INTERFACE_H */ diff --git a/src/nm-device.c b/src/nm-device.c index 6f7423b385..56634ef8fc 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -121,7 +121,8 @@ static gboolean nm_device_activate (NMDeviceInterface *device, NMActRequest *req, GError **error); static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason); -static gboolean nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs); +static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs); +static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections); static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self); @@ -139,7 +140,8 @@ device_interface_init (NMDeviceInterface *device_interface_class) device_interface_class->check_connection_compatible = check_connection_compatible; device_interface_class->activate = nm_device_activate; device_interface_class->deactivate = nm_device_deactivate; - device_interface_class->spec_match_list = nm_device_spec_match_list; + device_interface_class->spec_match_list = spec_match_list; + device_interface_class->connection_match_config = connection_match_config; } @@ -2202,25 +2204,45 @@ dispose (GObject *object) { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean take_down = TRUE; if (priv->disposed || !priv->initialized) goto out; priv->disposed = TRUE; + /* Don't down can-assume-connection capable devices that are activated with + * a connection that can be assumed. + */ + if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (self)) + && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) { + NMConnection *connection; + NMSettingIP4Config *s_ip4; + const char *method = NULL; + + /* Only system connections can be left up */ + connection = nm_act_request_get_connection (priv->act_request); + if ( connection + && (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM)) { + + /* Only static or DHCP connections can be left up */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + g_assert (s_ip4); + + method = nm_setting_ip4_config_get_method (s_ip4); + if ( !method + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + take_down = FALSE; + } + } + if (priv->failed_to_disconnected_id) { g_source_remove (priv->failed_to_disconnected_id); priv->failed_to_disconnected_id = 0; } - /* - * In dispose, you are supposed to free all types referenced from this - * object which might themselves hold a reference to self. Generally, - * the most simple solution is to unref all members on which you own a - * reference. - */ - - if (priv->managed) { + if (priv->managed && take_down) { NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; nm_device_take_down (self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); @@ -2231,7 +2253,8 @@ dispose (GObject *object) activation_source_clear (self, TRUE); - nm_device_set_use_dhcp (self, FALSE); + if (!take_down) + nm_device_set_use_dhcp (self, FALSE); if (priv->dnsmasq_manager) { if (priv->dnsmasq_state_id) { @@ -2577,7 +2600,7 @@ nm_device_set_managed (NMDevice *device, } static gboolean -nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs) +spec_match_list (NMDeviceInterface *device, const GSList *specs) { NMDevice *self; @@ -2590,6 +2613,16 @@ nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs) return FALSE; } +static NMConnection * +connection_match_config (NMDeviceInterface *device, const GSList *connections) +{ + g_return_val_if_fail (device != NULL, FALSE); + + if (NM_DEVICE_GET_CLASS (device)->connection_match_config) + return NM_DEVICE_GET_CLASS (device)->connection_match_config (NM_DEVICE (device), connections); + return NULL; +} + void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout) { diff --git a/src/nm-device.h b/src/nm-device.h index 31c58fb547..f3d63235e4 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -106,6 +106,8 @@ typedef struct { gboolean (* can_interrupt_activation) (NMDevice *self); gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); + + NMConnection * (* connection_match_config) (NMDevice *self, const GSList *connections); } NMDeviceClass; diff --git a/src/nm-manager.c b/src/nm-manager.c index 731589c40a..87338a10d5 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -348,12 +348,24 @@ manager_device_state_changed (NMDevice *device, /* Removes a device from a device list; returns the start of the new device list */ static GSList * -remove_one_device (NMManager *manager, GSList *list, NMDevice *device) +remove_one_device (NMManager *manager, + GSList *list, + NMDevice *device, + gboolean quitting) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - if (nm_device_get_managed (device)) - nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED); + if (nm_device_get_managed (device)) { + gboolean unmanage = !quitting; + + /* Don't unmanage active assume-connection-capable devices at shutdown */ + if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device)) + && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) + unmanage = FALSE; + + if (unmanage) + nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED); + } g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager); @@ -372,7 +384,7 @@ modem_removed (NMModemManager *modem_manager, NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - priv->devices = remove_one_device (self, priv->devices, modem); + priv->devices = remove_one_device (self, priv->devices, modem, FALSE); } static void @@ -1153,6 +1165,10 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; + GSList *connections = NULL; + NMConnection *existing; + GHashTableIter iter; + gpointer value; priv->devices = g_slist_append (priv->devices, device); @@ -1189,6 +1205,16 @@ add_device (NMManager *self, NMDevice *device) nm_info ("(%s): exported as %s", iface, path); g_free (path); + /* Check if we should assume the device's active connection by matching its + * config with an existing system connection. + */ + g_hash_table_iter_init (&iter, priv->system_connections); + while (g_hash_table_iter_next (&iter, NULL, &value)) + connections = g_slist_append (connections, value); + existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), + (const GSList *) connections); + g_slist_free (connections); + /* Start the device if it's supposed to be managed */ unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); if (!priv->sleeping && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) @@ -1302,7 +1328,7 @@ bluez_manager_resync_devices (NMManager *self) priv->devices = keep; while (g_slist_length (gone)) - gone = remove_one_device (self, gone, NM_DEVICE (gone->data)); + gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE); } else { g_slist_free (keep); g_slist_free (gone); @@ -1372,7 +1398,7 @@ bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, NMDevice *device = NM_DEVICE (iter->data); if (!strcmp (nm_device_get_udi (device), object_path)) { - priv->devices = remove_one_device (self, priv->devices, device); + priv->devices = remove_one_device (self, priv->devices, device, FALSE); break; } } @@ -1433,8 +1459,7 @@ udev_device_removed_cb (NMUdevManager *manager, ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); device = find_device_by_ifindex (self, ifindex); if (device) - priv->devices = remove_one_device (self, priv->devices, device); - + priv->devices = remove_one_device (self, priv->devices, device, FALSE); } static void @@ -2522,7 +2547,7 @@ dispose (GObject *object) while (g_slist_length (priv->devices)) { NMDevice *device = NM_DEVICE (priv->devices->data); - priv->devices = remove_one_device (manager, priv->devices, device); + priv->devices = remove_one_device (manager, priv->devices, device, TRUE); } user_destroy_connections (manager); From 78bb1c01b7e00275c27f20fbbac5ba507102c2fe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 5 Aug 2009 18:03:09 -0400 Subject: [PATCH 2/4] core: implement connection assumption Mark activation requests that contain connections to be assumed, and use that to short-circuit various parts of the activation process by not touching various device attributes, since they are already set up. Also ensure the device is not deactivated when it initially becomes managed, because that would kill the connection we are about to assume. --- include/NetworkManager.h | 3 ++ introspection/nm-device.xml | 5 +++ src/nm-activation-request.c | 12 +++++ src/nm-activation-request.h | 3 ++ src/nm-device.c | 87 +++++++++++++++++++++++++++---------- src/nm-manager.c | 56 +++++++++++++++++++----- 6 files changed, 132 insertions(+), 34 deletions(-) diff --git a/include/NetworkManager.h b/include/NetworkManager.h index fcef15bc7f..f755a4e4ca 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -357,6 +357,9 @@ typedef enum { /* Carrier/link changed */ NM_DEVICE_STATE_REASON_CARRIER, + /* The device's existing connection was assumed */ + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, + /* Unused */ NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index 952f1cf1ac..c743f831b2 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -370,6 +370,11 @@ The device's carrier/link changed. + + + + The device's existing connection was assumed. + diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index c919c5e710..45851d9938 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -76,6 +76,8 @@ typedef struct { GSList *share_rules; char *ac_path; + + gboolean assumed; } NMActRequestPrivate; enum { @@ -136,6 +138,7 @@ NMActRequest * nm_act_request_new (NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, gpointer *device) { GObject *object; @@ -160,6 +163,7 @@ nm_act_request_new (NMConnection *connection, NM_ACT_REQUEST (object)); priv->user_requested = user_requested; + priv->assumed = assumed; return NM_ACT_REQUEST (object); } @@ -643,3 +647,11 @@ nm_act_request_get_device (NMActRequest *req) return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device); } +gboolean +nm_act_request_get_assumed (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed; +} + diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 18760925f2..a3c0d97446 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -59,6 +59,7 @@ GType nm_act_request_get_type (void); NMActRequest *nm_act_request_new (NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, gpointer *device); /* An NMDevice */ NMConnection *nm_act_request_get_connection (NMActRequest *req); @@ -85,6 +86,8 @@ void nm_act_request_add_share_rule (NMActRequest *req, GObject * nm_act_request_get_device (NMActRequest *req); +gboolean nm_act_request_get_assumed (NMActRequest *req); + gboolean nm_act_request_get_secrets (NMActRequest *req, const char *setting_name, gboolean request_new, diff --git a/src/nm-device.c b/src/nm-device.c index 53e18f21ce..18a85160c7 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -140,8 +140,14 @@ static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReas static gboolean nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware); static gboolean nm_device_is_up (NMDevice *self); -static gboolean nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config, NMDeviceStateReason *reason); -static gboolean nm_device_set_ip6_config (NMDevice *dev, NMIP6Config *config, NMDeviceStateReason *reason); +static gboolean nm_device_set_ip4_config (NMDevice *dev, + NMIP4Config *config, + gboolean assumed, + NMDeviceStateReason *reason); +static gboolean nm_device_set_ip6_config (NMDevice *dev, + NMIP6Config *config, + gboolean assumed, + NMDeviceStateReason *reason); static void device_interface_init (NMDeviceInterface *device_interface_class) @@ -774,7 +780,7 @@ handle_autoip_change (NMDevice *self, NMDeviceStateReason *reason) g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config); - if (!nm_device_set_ip4_config (self, config, reason)) { + if (!nm_device_set_ip4_config (self, config, FALSE, reason)) { nm_warning ("(%s): failed to update IP4 config in response to autoip event.", nm_device_get_iface (self)); return FALSE; @@ -1724,19 +1730,20 @@ static gboolean nm_device_activate_stage5_ip_config_commit (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMIP4Config *ip4_config = NULL; NMIP6Config *ip6_config = NULL; const char *iface, *method = NULL; NMConnection *connection; NMSettingIP4Config *s_ip4; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + gboolean assumed; ip4_config = g_object_get_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP4_CONFIG); g_assert (ip4_config); ip6_config = g_object_get_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP6_CONFIG); - /* FIXME g_assert (ip6_config); */ /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, 0); @@ -1745,12 +1752,14 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) started...", iface); - if (!nm_device_set_ip4_config (self, ip4_config, &reason)) { + assumed = nm_act_request_get_assumed (priv->act_request); + + if (!nm_device_set_ip4_config (self, ip4_config, assumed, &reason)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } - if (!nm_device_set_ip6_config (self, ip6_config, &reason)) { + if (ip6_config && !nm_device_set_ip6_config (self, ip6_config, assumed, &reason)) { nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed", iface); } @@ -1776,7 +1785,8 @@ out: /* Balance IP config creation; device takes ownership in set_ip*_config() */ g_object_unref (ip4_config); - g_object_unref (ip6_config); + if (ip6_config) + g_object_unref (ip6_config); return FALSE; } @@ -1920,8 +1930,8 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason) nm_device_deactivate_quickly (self); /* Clean up nameservers and addresses */ - nm_device_set_ip4_config (self, NULL, &ignored); - nm_device_set_ip6_config (self, NULL, &ignored); + nm_device_set_ip4_config (self, NULL, FALSE, &ignored); + nm_device_set_ip6_config (self, NULL, FALSE, &ignored); /* Take out any entries in the routing table and any IP address the device had. */ nm_system_device_flush_routes (self); @@ -2022,13 +2032,22 @@ nm_device_activate (NMDeviceInterface *device, G_CALLBACK (connection_secrets_failed_cb), device); - /* HACK: update the state a bit early to avoid a race between the - * scheduled stage1 handler and nm_policy_device_change_check() thinking - * that the activation request isn't deferred because the deferred bit - * gets cleared a bit too early, when the connection becomes valid. - */ - nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - nm_device_activate_schedule_stage1_device_prepare (self); + if (!nm_act_request_get_assumed (req)) { + /* HACK: update the state a bit early to avoid a race between the + * scheduled stage1 handler and nm_policy_device_change_check() thinking + * that the activation request isn't deferred because the deferred bit + * gets cleared a bit too early, when the connection becomes valid. + */ + nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); + nm_device_activate_schedule_stage1_device_prepare (self); + } else { + /* If it's an assumed connection, let the device subclass short-circuit + * the normal connection process and just copy its IP configs from the + * interface. + */ + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); + nm_device_activate_schedule_stage3_ip_config_start (self); + } return TRUE; } @@ -2093,6 +2112,7 @@ handle_dhcp_lease_change (NMDevice *device) NMActRequest *req; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; const char *ip_iface; + gboolean assumed; if (!nm_device_get_use_dhcp (device)) { nm_warning ("got DHCP rebind for device that wasn't using DHCP."); @@ -2118,7 +2138,8 @@ handle_dhcp_lease_change (NMDevice *device) g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config); - if (nm_device_set_ip4_config (device, config, &reason)) { + assumed = nm_act_request_get_assumed (req); + if (nm_device_set_ip4_config (device, config, assumed, &reason)) { nm_dhcp4_config_reset (priv->dhcp4_config); nm_dhcp_manager_foreach_dhcp4_option (priv->dhcp_manager, ip_iface, @@ -2276,6 +2297,7 @@ nm_device_get_ip4_config (NMDevice *self) static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, + gboolean assumed, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -2311,8 +2333,13 @@ nm_device_set_ip4_config (NMDevice *self, if (new_config) { priv->ip4_config = g_object_ref (new_config); - success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff); - if (success) { + /* Don't touch the device's actual IP config if the connection is + * assumed when NM starts. + */ + if (!assumed) + success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff); + + if (success || assumed) { /* Export over D-Bus */ if (!nm_ip4_config_get_dbus_path (new_config)) nm_ip4_config_export (new_config); @@ -2373,6 +2400,7 @@ nm_device_update_ip4_address (NMDevice *self) static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *new_config, + gboolean assumed, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -2408,8 +2436,13 @@ nm_device_set_ip6_config (NMDevice *self, if (new_config) { priv->ip6_config = g_object_ref (new_config); - success = nm_system_apply_ip6_config (ip_iface, new_config, nm_device_get_priority (self), diff); - if (success) { + /* Don't touch the device's actual IP config if the connection is + * assumed when NM starts. + */ + if (!assumed) + success = nm_system_apply_ip6_config (ip_iface, new_config, nm_device_get_priority (self), diff); + + if (success || assumed) { /* Export over D-Bus */ if (!nm_ip6_config_get_dbus_path (new_config)) nm_ip6_config_export (new_config); @@ -2587,7 +2620,7 @@ dispose (GObject *object) NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; nm_device_take_down (self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); - nm_device_set_ip4_config (self, NULL, &ignored); + nm_device_set_ip4_config (self, NULL, FALSE, &ignored); } clear_act_request (self); @@ -2880,8 +2913,14 @@ nm_device_state_changed (NMDevice *device, if (!nm_device_bring_up (device, TRUE, &no_firmware) && no_firmware) nm_warning ("%s: firmware may be missing.", nm_device_get_iface (device)); } - /* Fall through, so when the device needs to be deactivated due to - * eg carrier changes we actually deactivate it */ + /* Ensure the device gets deactivated in response to stuff like + * carrier changes or rfkill. But don't deactivate devices that are + * about to assume a connection since that defeats the purpose of + * assuming the device's existing connection. + */ + if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) + nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason); + break; case NM_DEVICE_STATE_DISCONNECTED: if (old_state != NM_DEVICE_STATE_UNAVAILABLE) nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason); diff --git a/src/nm-manager.c b/src/nm-manager.c index 5ad0ff58cf..dc9da810e4 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -113,6 +113,14 @@ static void add_device (NMManager *self, NMDevice *device); static void hostname_provider_init (NMHostnameProvider *provider_class); +static const char *internal_activate_device (NMManager *manager, + NMDevice *device, + NMConnection *connection, + const char *specific_object, + gboolean user_requested, + gboolean assumed, + GError **error); + #define SSD_POKE_INTERVAL 120 #define ORIGDEV_TAG "originating-device" @@ -1165,7 +1173,6 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; - GSList *connections = NULL; NMConnection *existing; GHashTableIter iter; gpointer value; @@ -1208,20 +1215,47 @@ add_device (NMManager *self, NMDevice *device) /* Check if we should assume the device's active connection by matching its * config with an existing system connection. */ - g_hash_table_iter_init (&iter, priv->system_connections); - while (g_hash_table_iter_next (&iter, NULL, &value)) - connections = g_slist_append (connections, value); - existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), - (const GSList *) connections); - g_slist_free (connections); + if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))) { + GSList *connections = NULL; + + g_hash_table_iter_init (&iter, priv->system_connections); + while (g_hash_table_iter_next (&iter, NULL, &value)) + connections = g_slist_append (connections, value); + existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), + (const GSList *) connections); + g_slist_free (connections); + } /* Start the device if it's supposed to be managed */ unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); - if (!priv->sleeping && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) - nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED); + if ( !priv->sleeping + && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) { + nm_device_set_managed (device, + TRUE, + existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED : + NM_DEVICE_STATE_REASON_NOW_MANAGED); + } nm_sysconfig_settings_device_added (priv->sys_settings, device); g_signal_emit (self, signals[DEVICE_ADDED], 0, device); + + /* If the device has a connection it can assume, do that now */ + if (existing) { + const char *ac_path; + GError *error = NULL; + + ac_path = internal_activate_device (self, device, existing, NULL, FALSE, TRUE, &error); + if (ac_path) + g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); + else { + nm_warning ("Assumed connection (%d) %s failed to activate: (%d) %s", + nm_connection_get_scope (existing), + nm_connection_get_path (existing), + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + } + } } static gboolean @@ -1826,6 +1860,7 @@ internal_activate_device (NMManager *manager, NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, GError **error) { NMActRequest *req; @@ -1849,7 +1884,7 @@ internal_activate_device (NMManager *manager, NM_DEVICE_STATE_REASON_NONE); } - req = nm_act_request_new (connection, specific_object, user_requested, (gpointer) device); + req = nm_act_request_new (connection, specific_object, user_requested, assumed, (gpointer) device); g_signal_connect (req, "manager-get-secrets", G_CALLBACK (provider_get_secrets), manager); g_signal_connect (req, "manager-cancel-secrets", G_CALLBACK (provider_cancel_secrets), manager); success = nm_device_interface_activate (dev_iface, req, error); @@ -1961,6 +1996,7 @@ nm_manager_activate_connection (NMManager *manager, connection, specific_object, user_requested, + FALSE, error); } From 869e57524cc283150a6d885e75e25f50b3b02fb6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 6 Aug 2009 15:15:46 -0400 Subject: [PATCH 3/4] core: fix uninitialized variable usage --- src/nm-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index dc9da810e4..7e4155139d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1173,7 +1173,7 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; - NMConnection *existing; + NMConnection *existing = NULL; GHashTableIter iter; gpointer value; From 1d5a68db74a1e86155be9879a62fb1cbb86291ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 7 Aug 2009 12:13:54 -0500 Subject: [PATCH 4/4] ifcfg-rh: read iBFT config and convert to NM IPv4 config --- system-settings/plugins/ifcfg-rh/Makefile.am | 3 +- .../plugins/ifcfg-rh/nm-ifcfg-connection.c | 2 +- system-settings/plugins/ifcfg-rh/reader.c | 353 +++++++++++++-- system-settings/plugins/ifcfg-rh/reader.h | 5 +- .../plugins/ifcfg-rh/tests/Makefile.am | 9 + .../ifcfg-rh/tests/iscsiadm-test-bad-dns1 | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-dns2 | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-entry | 35 ++ .../ifcfg-rh/tests/iscsiadm-test-bad-gateway | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-ipaddr | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-record | 18 + .../plugins/ifcfg-rh/tests/iscsiadm-test-dhcp | 33 ++ .../ifcfg-rh/tests/iscsiadm-test-static | 35 ++ .../tests/network-scripts/Makefile.am | 4 +- .../network-scripts/ifcfg-test-ibft-dhcp | 4 + .../network-scripts/ifcfg-test-ibft-static | 4 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 415 +++++++++++++++++- 17 files changed, 958 insertions(+), 46 deletions(-) create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static create mode 100644 system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp create mode 100644 system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static diff --git a/system-settings/plugins/ifcfg-rh/Makefile.am b/system-settings/plugins/ifcfg-rh/Makefile.am index 1635e39484..e2b0a83c99 100644 --- a/system-settings/plugins/ifcfg-rh/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/Makefile.am @@ -32,7 +32,8 @@ libifcfg_rh_io_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ $(NSS_CFLAGS) \ -DG_DISABLE_DEPRECATED \ - -DSYSCONFDIR=\"$(sysconfdir)\" + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DSBINDIR=\"$(sbindir)\" libifcfg_rh_io_la_LIBADD = $(GLIB_LIBS) $(NSS_LIBS) diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 4767b5183c..5561df37ff 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -104,7 +104,7 @@ nm_ifcfg_connection_new (const char *filename, g_return_val_if_fail (filename != NULL, NULL); - wrapped = connection_from_file (filename, NULL, NULL, &unmanaged, &keyfile, error, ignore_error); + wrapped = connection_from_file (filename, NULL, NULL, NULL, &unmanaged, &keyfile, error, ignore_error); if (!wrapped) return NULL; diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index 61f3d68791..8d6b311d4c 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,284 @@ make_connection_setting (const char *file, return NM_SETTING (s_con); } +static gboolean +read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) +{ + char *value = NULL; + struct ether_addr *mac; + + g_return_val_if_fail (ifcfg != NULL, FALSE); + g_return_val_if_fail (array != NULL, FALSE); + g_return_val_if_fail (*array == NULL, FALSE); + g_return_val_if_fail (error != NULL, FALSE); + g_return_val_if_fail (*error == NULL, FALSE); + + value = svGetValue (ifcfg, "HWADDR", FALSE); + if (!value || !strlen (value)) { + g_free (value); + return TRUE; + } + + mac = ether_aton (value); + if (!mac) { + g_free (value); + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "The MAC address '%s' was invalid.", value); + return FALSE; + } + + g_free (value); + *array = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); + return TRUE; +} + +static void +iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED) +{ + /* We are in the child process here; set a different process group to + * ensure signal isolation between child and parent. + */ + pid_t pid = getpid (); + setpgid (pid, pid); +} + +static char * +match_iscsiadm_tag (const char *line, const char *tag, gboolean *skip) +{ + char *p; + + if (g_ascii_strncasecmp (line, tag, strlen (tag))) + return NULL; + + p = strchr (line, '='); + if (!p) { + g_warning ("%s: malformed iscsiadm record: no = in '%s'.", + __func__, line); + *skip = TRUE; + return NULL; + } + + p++; /* advance past = */ + return g_strstrip (p); +} + +#define ISCSI_HWADDR_TAG "iface.hwaddress" +#define ISCSI_BOOTPROTO_TAG "iface.bootproto" +#define ISCSI_IPADDR_TAG "iface.ipaddress" +#define ISCSI_SUBNET_TAG "iface.subnet_mask" +#define ISCSI_GATEWAY_TAG "iface.gateway" +#define ISCSI_DNS1_TAG "iface.primary_dns" +#define ISCSI_DNS2_TAG "iface.secondary_dns" + +static gboolean +fill_ip4_setting_from_ibft (shvarFile *ifcfg, + NMSettingIP4Config *s_ip4, + const char *iscsiadm_path, + GError **error) +{ + const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL }; + const char *envp[1] = { NULL }; + gboolean success = FALSE, in_record = FALSE, hwaddr_matched = FALSE, skip = FALSE; + char *out = NULL, *err = NULL; + gint status = 0; + GByteArray *ifcfg_mac = NULL; + char **lines = NULL, **iter; + const char *method = NULL; + struct in_addr ipaddr; + struct in_addr gateway; + struct in_addr dns1; + struct in_addr dns2; + guint32 prefix = 0; + + g_return_val_if_fail (s_ip4 != NULL, FALSE); + g_return_val_if_fail (iscsiadm_path != NULL, FALSE); + + if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0, + iscsiadm_child_setup, NULL, &out, &err, &status, error)) + return FALSE; + + if (!WIFEXITED (status)) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "%s exited abnormally.", iscsiadm_path); + goto done; + } + + if (WEXITSTATUS (status) != 0) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "%s exited with error %d. Message: '%s'", + iscsiadm_path, WEXITSTATUS (status), err ? err : "(none)"); + goto done; + } + + if (!read_mac_address (ifcfg, &ifcfg_mac, error)) + goto done; + /* Ensure we got a MAC */ + if (!ifcfg_mac) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "Missing device MAC address (no HWADDR tag present)."); + goto done; + } + + memset (&ipaddr, 0, sizeof (ipaddr)); + memset (&gateway, 0, sizeof (gateway)); + memset (&dns1, 0, sizeof (dns1)); + memset (&dns2, 0, sizeof (dns2)); + + /* Success, lets parse the output */ + lines = g_strsplit_set (out, "\n\r", -1); + for (iter = lines; iter && *iter; iter++) { + char *p; + + if (!g_ascii_strcasecmp (*iter, "# BEGIN RECORD")) { + if (in_record) { + g_warning ("%s: malformed iscsiadm record: already parsing record.", __func__); + skip = TRUE; + } + } else if (!g_ascii_strcasecmp (*iter, "# END RECORD")) { + if (!skip && hwaddr_matched) { + /* Record is good; fill IP4 config with its info */ + if (!method) { + g_warning ("%s: malformed iscsiadm record: missing BOOTPROTO.", __func__); + return FALSE; + } + + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL); + + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + NMIP4Address *addr; + + if (!ipaddr.s_addr || !prefix) { + g_warning ("%s: malformed iscsiadm record: BOOTPROTO=static " + "but missing IP address or prefix.", __func__); + return FALSE; + } + + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, ipaddr.s_addr); + nm_ip4_address_set_prefix (addr, prefix); + nm_ip4_address_set_gateway (addr, gateway.s_addr); + nm_setting_ip4_config_add_address (s_ip4, addr); + nm_ip4_address_unref (addr); + + if (dns1.s_addr) + nm_setting_ip4_config_add_dns (s_ip4, dns1.s_addr); + if (dns2.s_addr) + nm_setting_ip4_config_add_dns (s_ip4, dns2.s_addr); + + // FIXME: DNS search domains? + } + return TRUE; + } + skip = FALSE; + hwaddr_matched = FALSE; + memset (&ipaddr, 0, sizeof (ipaddr)); + memset (&gateway, 0, sizeof (gateway)); + memset (&dns1, 0, sizeof (dns1)); + memset (&dns2, 0, sizeof (dns2)); + prefix = 0; + method = NULL; + } + + if (skip) + continue; + + /* HWADDR */ + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_HWADDR_TAG, &skip))) { + struct ether_addr *ibft_mac; + + ibft_mac = ether_aton (p); + if (!ibft_mac) { + g_warning ("%s: malformed iscsiadm record: invalid hwaddress.", __func__); + skip = TRUE; + continue; + } + + if (memcmp (ifcfg_mac->data, (guint8 *) ibft_mac->ether_addr_octet, ETH_ALEN)) { + /* This record isn't for the current device, ignore it */ + skip = TRUE; + continue; + } + + /* Success, this record is for this device */ + hwaddr_matched = TRUE; + } + + /* BOOTPROTO */ + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_BOOTPROTO_TAG, &skip))) { + if (!g_ascii_strcasecmp (p, "dhcp")) + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + else if (!g_ascii_strcasecmp (p, "static")) + method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + else { + g_warning ("%s: malformed iscsiadm record: unknown BOOTPROTO '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_IPADDR_TAG, &skip))) { + if (inet_pton (AF_INET, p, &ipaddr) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid IP address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_SUBNET_TAG, &skip))) { + struct in_addr mask; + + if (inet_pton (AF_INET, p, &mask) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid subnet mask '%s'.", + __func__, p); + skip = TRUE; + continue; + } + + prefix = nm_utils_ip4_netmask_to_prefix (mask.s_addr); + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_GATEWAY_TAG, &skip))) { + if (inet_pton (AF_INET, p, &gateway) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid IP gateway '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS1_TAG, &skip))) { + if (inet_pton (AF_INET, p, &dns1) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid DNS1 address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS2_TAG, &skip))) { + if (inet_pton (AF_INET, p, &dns2) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid DNS2 address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + } + + success = TRUE; + +done: + if (ifcfg_mac) + g_byte_array_free (ifcfg_mac, TRUE); + g_strfreev (lines); + g_free (out); + g_free (err); + return success; +} + static gboolean read_ip4_address (shvarFile *ifcfg, const char *tag, @@ -325,7 +604,10 @@ error: } static NMSetting * -make_ip4_setting (shvarFile *ifcfg, const char *network_file, GError **error) +make_ip4_setting (shvarFile *ifcfg, + const char *network_file, + const char *iscsiadm_path, + GError **error) { NMSettingIP4Config *s_ip4 = NULL; char *value = NULL; @@ -364,7 +646,15 @@ make_ip4_setting (shvarFile *ifcfg, const char *network_file, GError **error) if (value) { if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - else if (!g_ascii_strcasecmp (value, "autoip")) { + else if (!g_ascii_strcasecmp (value, "ibft")) { + /* iSCSI Boot Firmware Table: need to read values from the iSCSI + * firmware for this device and create the IP4 setting using those. + */ + if (fill_ip4_setting_from_ibft (ifcfg, s_ip4, iscsiadm_path, error)) + return NM_SETTING (s_ip4); + g_object_unref (s_ip4); + return NULL; + } else if (!g_ascii_strcasecmp (value, "autoip")) { g_free (value); g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, @@ -498,38 +788,6 @@ error: return NULL; } -static gboolean -read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) -{ - char *value = NULL; - struct ether_addr *mac; - - g_return_val_if_fail (ifcfg != NULL, FALSE); - g_return_val_if_fail (array != NULL, FALSE); - g_return_val_if_fail (*array == NULL, FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); - - value = svGetValue (ifcfg, "HWADDR", FALSE); - if (!value || !strlen (value)) { - g_free (value); - return TRUE; - } - - mac = ether_aton (value); - if (!mac) { - g_free (value); - g_set_error (error, ifcfg_plugin_error_quark (), 0, - "The MAC address '%s' was invalid.", value); - return FALSE; - } - - g_free (value); - *array = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); - return TRUE; -} - static gboolean add_one_wep_key (shvarFile *ifcfg, const char *shvar_key, @@ -2032,8 +2290,9 @@ is_wireless_device (const char *iface) NMConnection * connection_from_file (const char *filename, - const char *network_file, - const char *test_type, /* for unit tests only */ + const char *network_file, /* for unit tests only */ + const char *test_type, /* for unit tests only */ + const char *iscsiadm_path, /* for unit tests only */ char **unmanaged, char **keyfile, GError **error, @@ -2041,7 +2300,7 @@ connection_from_file (const char *filename, { NMConnection *connection = NULL; shvarFile *parsed; - char *type, *nmc = NULL; + char *type, *nmc = NULL, *bootproto; NMSetting *s_ip4; char *ifcfg_name = NULL; gboolean nm_controlled = TRUE; @@ -2056,6 +2315,9 @@ connection_from_file (const char *filename, if (!network_file) network_file = SYSCONFDIR "/sysconfig/network"; + if (!iscsiadm_path) + iscsiadm_path = SBINDIR "/iscsiadm"; + ifcfg_name = utils_get_ifcfg_name (filename); if (!ifcfg_name) { g_set_error (error, ifcfg_plugin_error_quark (), 0, @@ -2142,7 +2404,7 @@ connection_from_file (const char *filename, if (!connection || *unmanaged) goto done; - s_ip4 = make_ip4_setting (parsed, network_file, error); + s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, error); if (*error) { g_object_unref (connection); connection = NULL; @@ -2151,6 +2413,21 @@ connection_from_file (const char *filename, nm_connection_add_setting (connection, s_ip4); } + /* iSCSI / ibft connections are read-only since their settings are + * stored in NVRAM and can only be changed in BIOS. + */ + bootproto = svGetValue (parsed, "BOOTPROTO", FALSE); + if ( bootproto + && connection + && !g_ascii_strcasecmp (bootproto, "ibft")) { + NMSettingConnection *s_con; + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL); + } + if (!nm_connection_verify (connection, error)) { g_object_unref (connection); connection = NULL; diff --git a/system-settings/plugins/ifcfg-rh/reader.h b/system-settings/plugins/ifcfg-rh/reader.h index 458223fce8..f453045571 100644 --- a/system-settings/plugins/ifcfg-rh/reader.h +++ b/system-settings/plugins/ifcfg-rh/reader.h @@ -27,8 +27,9 @@ #include "shvar.h" NMConnection *connection_from_file (const char *filename, - const char *network_file, - const char *test_type, + const char *network_file, /* for unit tests only */ + const char *test_type, /* for unit tests only */ + const char *iscsiadm_path, /* for unit tests only */ char **unmanaged, char **keyfile, GError **error, diff --git a/system-settings/plugins/ifcfg-rh/tests/Makefile.am b/system-settings/plugins/ifcfg-rh/tests/Makefile.am index d898cc5ab2..195ab1fc8d 100644 --- a/system-settings/plugins/ifcfg-rh/tests/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/tests/Makefile.am @@ -30,3 +30,12 @@ check-local: test-ifcfg-rh endif +EXTRA_DIST = \ + iscsiadm-test-dhcp \ + iscsiadm-test-static \ + iscsiadm-test-malformed \ + iscsiadm-test-bad-ipaddr \ + iscsiadm-test-bad-gateway \ + iscsiadm-test-bad-dns1 \ + iscsiadm-test-bad-dns2 + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 new file mode 100755 index 0000000000..4a6a93822e --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10000.500.250.1 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 new file mode 100755 index 0000000000..9bd5839bd3 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = blah.foo.bar.baz +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry new file mode 100755 index 0000000000..eba0ec6730 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry @@ -0,0 +1,35 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway new file mode 100755 index 0000000000..b3dc74478b --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = aa.bb.cc.dd +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr new file mode 100755 index 0000000000..92f44777b4 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = bb.cc.dd.ee +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record new file mode 100755 index 0000000000..a2d215fe24 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record @@ -0,0 +1,18 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp new file mode 100755 index 0000000000..6de0637cb1 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp @@ -0,0 +1,33 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static new file mode 100755 index 0000000000..99a6e7c173 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static @@ -0,0 +1,35 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index 01532b7c5b..206b206e15 100644 --- a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -35,7 +35,9 @@ EXTRA_DIST = \ ifcfg-test-wifi-wpa-eap-ttls-tls \ keys-test-wifi-wpa-eap-ttls-tls \ test_ca_cert.pem \ - test1_key_and_cert.pem + test1_key_and_cert.pem \ + ifcfg-test-ibft-dhcp \ + ifcfg-test-ibft-static check-local: @for f in $(EXTRA_DIST); do \ diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp new file mode 100644 index 0000000000..abfcd6e4ce --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp @@ -0,0 +1,4 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +DEVICE=eth0 +HWADDR=00:33:21:98:b9:f1 +BOOTPROTO=ibft diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static new file mode 100644 index 0000000000..99b02e42b1 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static @@ -0,0 +1,4 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +DEVICE=eth0 +HWADDR=00:33:21:98:b9:f0 +BOOTPROTO=ibft diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 213aeab148..2afb147b9b 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -176,6 +176,7 @@ test_read_minimal (void) connection = connection_from_file (TEST_IFCFG_MINIMAL, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -299,6 +300,7 @@ test_read_unmanaged (void) connection = connection_from_file (TEST_IFCFG_UNMANAGED, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -417,6 +419,7 @@ test_read_wired_static (void) connection = connection_from_file (TEST_IFCFG_WIRED_STATIC, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -557,7 +560,7 @@ test_read_wired_static (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24, - "wired-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + "wired-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", TEST_IFCFG_WIRED_STATIC, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -612,6 +615,7 @@ test_read_wired_dhcp (void) connection = connection_from_file (TEST_IFCFG_WIRED_DHCP, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -777,6 +781,7 @@ test_read_wired_global_gateway (void) connection = connection_from_file (TEST_IFCFG_WIRED_GLOBAL_GATEWAY, TEST_NETWORK_WIRED_GLOBAL_GATEWAY, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -844,7 +849,7 @@ test_read_wired_global_gateway (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24, - "wired-global-gateway-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + "wired-global-gateway-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", TEST_IFCFG_WIRED_GLOBAL_GATEWAY, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -894,6 +899,7 @@ test_read_wired_never_default (void) connection = connection_from_file (TEST_IFCFG_WIRED_NEVER_DEFAULT, TEST_NETWORK_WIRED_NEVER_DEFAULT, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -983,6 +989,7 @@ test_read_onboot_no (void) connection = connection_from_file (TEST_IFCFG_ONBOOT_NO, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -1039,6 +1046,7 @@ test_read_wired_8021x_peap_mschapv2 (void) connection = connection_from_file (TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -1226,6 +1234,7 @@ test_read_wifi_open (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1394,6 +1403,7 @@ test_read_wifi_open_ssid_hex (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_HEX, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1463,7 +1473,14 @@ test_read_wifi_open_ssid_bad (const char *file, const char *test) gboolean ignore_error = FALSE; GError *error = NULL; - connection = connection_from_file (file, NULL, TYPE_WIRELESS, &unmanaged, &keyfile, &error, &ignore_error); + connection = connection_from_file (file, + NULL, + TYPE_WIRELESS, + NULL, + &unmanaged, + &keyfile, + &error, + &ignore_error); ASSERT (connection == NULL, test, "unexpected success reading %s", file); g_clear_error (&error); } @@ -1488,6 +1505,7 @@ test_read_wifi_open_ssid_quoted (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_QUOTED, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1575,6 +1593,7 @@ test_read_wifi_wep (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1835,6 +1854,7 @@ test_read_wifi_wep_adhoc (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP_ADHOC, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2088,6 +2108,7 @@ test_read_wifi_leap (void) connection = connection_from_file (TEST_IFCFG_WIFI_LEAP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2235,6 +2256,7 @@ test_read_wifi_wpa_psk (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2533,6 +2555,7 @@ test_read_wifi_wpa_psk_adhoc (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_ADHOC, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2715,6 +2738,7 @@ test_read_wifi_wpa_psk_hex (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_HEX, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2861,6 +2885,7 @@ test_read_wifi_wpa_eap_tls (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TLS, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -2995,6 +3020,7 @@ test_read_wifi_wpa_eap_ttls_tls (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3152,6 +3178,7 @@ test_read_wifi_wep_eap_ttls_chap (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3402,6 +3429,7 @@ test_write_wired_static (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3500,6 +3528,7 @@ test_write_wired_dhcp (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3618,6 +3647,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3742,6 +3772,7 @@ test_write_wifi_open (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3846,6 +3877,7 @@ test_write_wifi_open_hex_ssid (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3970,6 +4002,7 @@ test_write_wifi_wep (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4114,6 +4147,7 @@ test_write_wifi_wep_adhoc (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4263,6 +4297,7 @@ test_write_wifi_wpa_psk (const char *name, reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4407,6 +4442,7 @@ test_write_wifi_wpa_psk_adhoc (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4566,6 +4602,7 @@ test_write_wifi_wpa_eap_tls (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4742,6 +4779,7 @@ test_write_wifi_wpa_eap_ttls_tls (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4893,6 +4931,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4917,6 +4956,366 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void) g_object_unref (reread); } +#define TEST_IFCFG_IBFT_DHCP TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft-dhcp" + +static void +test_read_ibft_dhcp (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + const char *tmp; + const GByteArray *array; + char expected_mac_address[ETH_ALEN] = { 0x00, 0x33, 0x21, 0x98, 0xb9, 0xf1 }; + const char *expected_id = "System test-ibft-dhcp"; + guint64 expected_timestamp = 0; + + connection = connection_from_file (TEST_IFCFG_IBFT_DHCP, + NULL, + TYPE_ETHERNET, + TEST_IFCFG_DIR "/iscsiadm-test-dhcp", + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection != NULL, + "ibft-dhcp-read", "failed to read %s: %s", TEST_IFCFG_IBFT_DHCP, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "ibft-dhcp-verify", "failed to verify %s: %s", TEST_IFCFG_IBFT_DHCP, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "ibft-dhcp-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "ibft-dhcp-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID can't be tested if the ifcfg does not contain the UUID key, because + * the UUID is generated on the full path of the ifcfg file, which can change + * depending on where the tests are run. + */ + + /* Timestamp */ + ASSERT (nm_setting_connection_get_timestamp (s_con) == expected_timestamp, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TIMESTAMP); + + /* Autoconnect */ + ASSERT (nm_setting_connection_get_autoconnect (s_con) == TRUE, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT); + + /* Read-only */ + ASSERT (nm_setting_connection_get_read_only (s_con) == TRUE, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_READ_ONLY); + + /* ===== WIRED SETTING ===== */ + + s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)); + ASSERT (s_wired != NULL, + "ibft-dhcp-verify-wired", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME); + + /* MAC address */ + array = nm_setting_wired_get_mac_address (s_wired); + ASSERT (array != NULL, + "ibft-dhcp-verify-wired", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (array->len == ETH_ALEN, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value length", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (memcmp (array->data, &expected_mac_address[0], sizeof (expected_mac_address)) == 0, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + + ASSERT (nm_setting_wired_get_mtu (s_wired) == 0, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MTU); + + /* ===== IPv4 SETTING ===== */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); + ASSERT (s_ip4 != NULL, + "ibft-dhcp-verify-ip4", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_IP4_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, + "ibft-dhcp-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + + g_object_unref (connection); +} + +#define TEST_IFCFG_IBFT_STATIC TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft-static" + +static void +test_read_ibft_static (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + const char *tmp; + const GByteArray *array; + char expected_mac_address[ETH_ALEN] = { 0x00, 0x33, 0x21, 0x98, 0xb9, 0xf0 }; + const char *expected_id = "System test-ibft-static"; + guint64 expected_timestamp = 0; + const char *expected_dns1 = "10.16.255.2"; + const char *expected_dns2 = "10.16.255.3"; + struct in_addr addr; + const char *expected_address1 = "192.168.32.72"; + const char *expected_address1_gw = "192.168.35.254"; + NMIP4Address *ip4_addr; + + connection = connection_from_file (TEST_IFCFG_IBFT_STATIC, + NULL, + TYPE_ETHERNET, + TEST_IFCFG_DIR "/iscsiadm-test-static", + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection != NULL, + "ibft-static-read", "failed to read %s: %s", TEST_IFCFG_IBFT_STATIC, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "ibft-static-verify", "failed to verify %s: %s", TEST_IFCFG_IBFT_STATIC, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "ibft-static-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "ibft-static-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID can't be tested if the ifcfg does not contain the UUID key, because + * the UUID is generated on the full path of the ifcfg file, which can change + * depending on where the tests are run. + */ + + /* Timestamp */ + ASSERT (nm_setting_connection_get_timestamp (s_con) == expected_timestamp, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TIMESTAMP); + + /* Autoconnect */ + ASSERT (nm_setting_connection_get_autoconnect (s_con) == TRUE, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT); + + /* Read-only */ + ASSERT (nm_setting_connection_get_read_only (s_con) == TRUE, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_READ_ONLY); + + /* ===== WIRED SETTING ===== */ + + s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)); + ASSERT (s_wired != NULL, + "ibft-static-verify-wired", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME); + + /* MAC address */ + array = nm_setting_wired_get_mac_address (s_wired); + ASSERT (array != NULL, + "ibft-static-verify-wired", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (array->len == ETH_ALEN, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value length", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (memcmp (array->data, &expected_mac_address[0], sizeof (expected_mac_address)) == 0, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + + ASSERT (nm_setting_wired_get_mtu (s_wired) == 0, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MTU); + + /* ===== IPv4 SETTING ===== */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); + ASSERT (s_ip4 != NULL, + "ibft-static-verify-ip4", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + + /* DNS Addresses */ + ASSERT (nm_setting_ip4_config_get_num_dns (s_ip4) == 2, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET, expected_dns1, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert DNS IP address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 0) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET, expected_dns2, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert DNS IP address #2", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 1) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value #2", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 1, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + /* Address #1 */ + ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 0); + ASSERT (ip4_addr, + "ibft-static-verify-ip4", "failed to verify %s: missing IP4 address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 22, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET, expected_address1, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert IP address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_ip4_address_get_address (ip4_addr) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET, expected_address1_gw, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert IP address #1 gateway", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + ASSERT (nm_ip4_address_get_gateway (ip4_addr) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + g_object_unref (connection); +} + +static void +test_read_ibft_malformed (const char *name, const char *iscsiadm_path) +{ + NMConnection *connection; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_IBFT_STATIC, + NULL, + TYPE_ETHERNET, + iscsiadm_path, + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection == NULL, + name, "unexpectedly able to read %s", TEST_IFCFG_IBFT_STATIC); +} + static void test_write_wired_pppoe (void) { @@ -5236,6 +5635,16 @@ int main (int argc, char **argv) test_write_wifi_wpa_eap_ttls_tls (); test_write_wifi_wpa_eap_ttls_mschapv2 (); + /* iSCSI / ibft */ + test_read_ibft_dhcp (); + test_read_ibft_static (); + test_read_ibft_malformed ("ibft-bad-record-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-record"); + test_read_ibft_malformed ("ibft-bad-entry-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-entry"); + test_read_ibft_malformed ("ibft-bad-ipaddr-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-ipaddr"); + test_read_ibft_malformed ("ibft-bad-gateway-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-gateway"); + test_read_ibft_malformed ("ibft-bad-dns1-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns1"); + test_read_ibft_malformed ("ibft-bad-dns2-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns2"); + /* Stuff we expect to fail for now */ test_write_wired_pppoe (); test_write_vpn ();