core: combine and apply IPv4 configs instead of applying directly

Like IPv6, keep the DHCP/LLv4 config separate and combine it with the
NMSettingIP4Config to arrive at the final, combined IP4 config.  This
brings the behavior in line with IPv6 code flow and will allow adding
the VPN routes config into the mix more easily.
This commit is contained in:
Dan Williams 2013-08-01 10:34:46 -05:00
parent 1923f54d79
commit 468243baf2
3 changed files with 141 additions and 80 deletions

View file

@ -72,9 +72,6 @@ static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *con
#include "nm-device-glue.h"
#define PENDING_IP4_CONFIG "pending-ip4-config"
#define PENDING_IP6_CONFIG "pending-ip6-config"
#define DBUS_G_TYPE_UINT_STRUCT (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID))
/* default to installed helper, but can be modified for testing */
@ -228,8 +225,11 @@ typedef struct {
GByteArray * dhcp_anycast_address;
/* IP4 configuration info */
NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */
NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */
IpState ip4_state;
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
/* DHCPv4 tracking */
NMDHCPClient * dhcp4_client;
gulong dhcp4_state_sigid;
gulong dhcp4_timeout_sigid;
@ -299,6 +299,10 @@ static gboolean nm_device_set_ip4_config (NMDevice *dev,
NMIP4Config *config,
gboolean commit,
NMDeviceStateReason *reason);
static gboolean ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
NMDeviceStateReason *out_reason);
static gboolean nm_device_set_ip6_config (NMDevice *dev,
NMIP6Config *config,
gboolean commit,
@ -2035,21 +2039,6 @@ aipd_get_ip4_config (NMDevice *self, struct in_addr lla)
return config;
}
static void
autoip_changed (NMDevice *self,
NMIP4Config *config,
NMSettingIP4Config *s_ip4)
{
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
nm_ip4_config_merge_setting (config, s_ip4);
if (!nm_device_set_ip4_config (self, config, TRUE, &reason)) {
nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config in response to autoip event.",
nm_device_get_iface (self));
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
}
}
#define IPV4LL_NETWORK (htonl (0xA9FE0000L))
#define IPV4LL_NETMASK (htonl (0xFFFF0000L))
@ -2062,6 +2051,7 @@ nm_device_handle_autoip4_event (NMDevice *self,
NMConnection *connection = NULL;
NMSettingIP4Config *s_ip4 = NULL;
const char *iface, *method = NULL;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
g_return_if_fail (event != NULL);
@ -2110,7 +2100,11 @@ nm_device_handle_autoip4_event (NMDevice *self,
aipd_timeout_remove (self);
nm_device_activate_schedule_ip4_config_result (self, config);
} else if (priv->ip4_state == IP_DONE) {
autoip_changed (self, config, s_ip4);
if (!ip4_config_merge_and_apply (self, config, &reason)) {
nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config for autoip change.",
nm_device_get_iface (self));
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
}
} else
g_assert_not_reached ();
@ -2275,34 +2269,61 @@ dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data)
(const char *) value);
}
static void
dhcp4_lease_change (NMDevice *device, NMIP4Config *config)
static gboolean
ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
NMDeviceStateReason *out_reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
gboolean success;
NMIP4Config *composite;
if (config == NULL) {
nm_log_warn (LOGD_DHCP4, "(%s): failed to get DHCPv4 config for rebind",
nm_device_get_ip_iface (device));
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
return;
}
connection = nm_device_get_connection (device);
connection = nm_device_get_connection (self);
g_assert (connection);
/* Merge with user overrides */
nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection));
if (!nm_device_set_ip4_config (device, config, TRUE, &reason)) {
nm_log_warn (LOGD_DHCP4, "(%s): failed to update IPv4 config in response to DHCP event.",
nm_device_get_ip_iface (device));
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
return;
/* Merge all the configs into the composite config */
if (config) {
g_clear_object (&priv->dev_ip4_config);
priv->dev_ip4_config = g_object_ref (config);
}
/* Notify dispatcher scripts of new DHCP4 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, connection, device, NULL, NULL);
g_assert (priv->dev_ip4_config);
composite = nm_ip4_config_new ();
nm_ip4_config_merge (composite, priv->dev_ip4_config);
/* Merge user overrides into the composite config */
nm_ip4_config_merge_setting (composite, nm_connection_get_setting_ip4_config (connection));
/* Allow setting MTU etc */
if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
success = nm_device_set_ip4_config (self, composite, TRUE, out_reason);
g_object_unref (composite);
return success;
}
static void
dhcp4_lease_change (NMDevice *self, NMIP4Config *config)
{
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
g_return_if_fail (config != NULL);
if (!ip4_config_merge_and_apply (self, config, &reason)) {
nm_log_warn (LOGD_DHCP4, "(%s): failed to update IPv4 config for DHCP change.",
nm_device_get_ip_iface (self));
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
} else {
/* Notify dispatcher scripts of new DHCP4 config */
nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE,
nm_device_get_connection (self),
self,
NULL,
NULL);
}
}
static void
@ -2341,21 +2362,27 @@ dhcp4_state_changed (NMDHCPClient *client,
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
case DHC_REBIND4: /* new, different lease */
config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
if (!config) {
nm_log_warn (LOGD_DHCP4, "(%s): failed to get IPv4 config in response to DHCP event.",
nm_device_get_ip_iface (device));
nm_device_state_changed (device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
break;
}
if (priv->ip4_state == IP_CONF)
nm_device_activate_schedule_ip4_config_result (device, config);
else if (priv->ip4_state == IP_DONE)
dhcp4_lease_change (device, config);
g_object_unref (config);
if (config) {
/* Update the DHCP4 config object with new DHCP options */
nm_dhcp4_config_reset (priv->dhcp4_config);
nm_dhcp_client_foreach_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG);
g_object_unref (config);
}
/* Update the DHCP4 config object with new DHCP options */
nm_dhcp4_config_reset (priv->dhcp4_config);
nm_dhcp_client_foreach_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG);
break;
case DHC_TIMEOUT: /* timed out contacting DHCP server */
dhcp4_fail (device, TRUE);
@ -3723,7 +3750,6 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
NMIP4Config *config = NULL;
const char *iface, *method = NULL;
NMConnection *connection;
NMSettingIP4Config *s_ip4;
@ -3742,22 +3768,13 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
connection = nm_act_request_get_connection (req);
g_assert (connection);
config = g_object_get_data (G_OBJECT (req), PENDING_IP4_CONFIG);
g_assert (config);
/* Make sure the interface is up again just because */
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex && !nm_platform_link_is_up (ifindex))
nm_platform_link_set_up (ifindex);
/* Allow setting MTU etc */
if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, config);
/* Merge with user overrides */
nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection));
if (!nm_device_set_ip4_config (self, config, TRUE, &reason)) {
/* NULL to use the existing priv->dev_ip4_config */
if (!ip4_config_merge_and_apply (self, NULL, &reason)) {
nm_log_info (LOGD_DEVICE | LOGD_IP4,
"Activation (%s) Stage 5 of 5 (IPv4 Commit) failed",
iface);
@ -3771,7 +3788,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
method = nm_setting_ip4_config_get_method (s_ip4);
if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) {
if (!start_sharing (self, config)) {
if (!start_sharing (self, priv->ip4_config)) {
nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IPv4 Commit) start sharing failed.", iface);
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
goto out;
@ -3787,9 +3804,6 @@ out:
nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv4 Commit) complete.",
iface);
/* Balance IP config creation; nm_device_set_ip4_config() takes a reference */
g_object_set_data (G_OBJECT (req), PENDING_IP4_CONFIG, NULL);
return FALSE;
}
@ -3799,19 +3813,11 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (NM_IS_IP4_CONFIG (config));
priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (priv->act_request);
if (config == NULL) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
return;
}
g_object_set_data_full (G_OBJECT (priv->act_request),
PENDING_IP4_CONFIG,
g_object_ref (config),
g_object_unref);
g_clear_object (&priv->dev_ip4_config);
priv->dev_ip4_config = g_object_ref (config);
activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET);
@ -4354,7 +4360,6 @@ nm_device_set_ip4_config (NMDevice *self,
int ip_ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (reason != NULL, FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
ip_iface = nm_device_get_ip_iface (self);
@ -4383,6 +4388,9 @@ nm_device_set_ip4_config (NMDevice *self,
if (!success && reason)
*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
} else {
/* Device config is invalid if combined config is invalid */
g_clear_object (&priv->dev_ip4_config);
}
g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG);
@ -4407,7 +4415,6 @@ nm_device_set_ip6_config (NMDevice *self,
int ip_ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (reason != NULL, FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
ip_iface = nm_device_get_ip_iface (self);
@ -4792,6 +4799,8 @@ dispose (GObject *object)
nm_device_take_down (self, FALSE);
}
g_clear_object (&priv->dev_ip4_config);
g_clear_object (&priv->ip4_config);
/* reset the saved RA value */
if (priv->ip6_accept_ra_path) {

View file

@ -330,6 +330,57 @@ nm_ip4_config_update_setting (NMIP4Config *config, NMSettingIP4Config *setting)
/******************************************************************/
void
nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src)
{
guint32 i;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
/* addresses */
for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++)
nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i));
/* ptp address; only replace if src doesn't have one */
if (!nm_ip4_config_get_ptp_address (dst))
nm_ip4_config_set_ptp_address (dst, nm_ip4_config_get_ptp_address (src));
/* nameservers */
for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++)
nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i));
/* default gateway */
if (!nm_ip4_config_get_gateway (dst))
nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src));
/* routes */
for (i = 0; i < nm_ip4_config_get_num_routes (src); i++)
nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i));
/* domains */
for (i = 0; i < nm_ip4_config_get_num_domains (src); i++)
nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i));
/* dns searches */
for (i = 0; i < nm_ip4_config_get_num_searches (src); i++)
nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i));
if (!nm_ip4_config_get_mss (dst))
nm_ip4_config_set_mss (dst, nm_ip4_config_get_mss (src));
/* NIS */
for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++)
nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i));
if (nm_ip4_config_get_nis_domain (src))
nm_ip4_config_set_nis_domain (dst, nm_ip4_config_get_nis_domain (src));
/* WINS */
for (i = 0; i < nm_ip4_config_get_num_wins (src); i++)
nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i));
}
gboolean
nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 network, int plen)
{

View file

@ -64,6 +64,7 @@ void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setti
void nm_ip4_config_update_setting (NMIP4Config *config, NMSettingIP4Config *setting);
/* Utility functions */
void nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src);
gboolean nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 dest, int plen);
/* Gateways */