summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2016-10-31 23:29:51 +0100
committerLubomir Rintel <lkundrak@v3.sk>2016-11-01 10:03:11 +0100
commit7a839370387010fd853bc85f8e853e51c5b21536 (patch)
treeef0c952588872c74c4eeb4b479ab9ca518ce73f4
parent4b9dfb8ae063b2a2d136ec780b85d1541877330c (diff)
downloadNetworkManager-7a839370387010fd853bc85f8e853e51c5b21536.tar.gz
device: add prefix delegation machinery
Two parts: contributing the prefixes delegated to the requesting (uplink) interface to the policy's pool and applying the negotiated subjects on the shared (downlink) devices.
-rw-r--r--src/devices/nm-device.c110
-rw-r--r--src/devices/nm-device.h10
2 files changed, 117 insertions, 3 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 886af3f1c8..106fa15f82 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -83,6 +83,8 @@ enum {
AUTH_REQUEST,
IP4_CONFIG_CHANGED,
IP6_CONFIG_CHANGED,
+ IP6_PREFIX_DELEGATED,
+ IP6_SUBNET_NEEDED,
REMOVED,
RECHECK_AUTO_ACTIVATE,
RECHECK_ASSUME,
@@ -389,6 +391,7 @@ typedef struct _NMDevicePrivate {
NMDhcpClient * client;
NMNDiscDHCPLevel mode;
gulong state_sigid;
+ gulong prefix_sigid;
NMDhcp6Config * config;
/* IP6 config from DHCP */
NMIP6Config * ip6_config;
@@ -396,8 +399,11 @@ typedef struct _NMDevicePrivate {
char * event_id;
guint restart_id;
guint num_tries_left;
+ guint needed_prefixes;
} dhcp6;
+ gboolean needs_ip6_subnet;
+
/* allow autoconnect feature */
bool autoconnect;
@@ -5474,6 +5480,7 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release)
if (priv->dhcp6.client) {
nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid);
+ nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.prefix_sigid);
if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE
|| cleanup_type == CLEANUP_TYPE_REMOVED)
@@ -5928,6 +5935,19 @@ dhcp6_state_changed (NMDhcpClient *client,
}
}
+static void
+dhcp6_prefix_delegated (NMDhcpClient *client,
+ NMPlatformIP6Address *prefix,
+ gpointer user_data)
+{
+ NMDevice *self = NM_DEVICE (user_data);
+
+ /* Just re-emit. The device just contributes the prefix to the
+ * pool in NMPolicy, which decides about subnet allocation
+ * on the shared devices. */
+ g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix);
+}
+
static gboolean
dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
{
@@ -5965,7 +5985,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
priv->dhcp_timeout,
priv->dhcp_anycast_address,
(priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
- nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)));
+ nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)),
+ priv->dhcp6.needed_prefixes);
if (tmp)
g_byte_array_free (tmp, TRUE);
@@ -5974,6 +5995,10 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
G_CALLBACK (dhcp6_state_changed),
self);
+ priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client,
+ NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
+ G_CALLBACK (dhcp6_prefix_delegated),
+ self);
}
return !!priv->dhcp6.client;
@@ -6040,6 +6065,53 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release)
/*****************************************************************************/
+/*
+ * Called on the requesting interface when a subnet can't be obtained
+ * from known prefixes for a newly active shared connection.
+ */
+void
+nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ _LOGD (LOGD_IP6, "ipv6-pd: asking DHCP6 for %d prefixes", needed_prefixes);
+ priv->dhcp6.needed_prefixes = needed_prefixes;
+ nm_device_dhcp6_renew (self, FALSE);
+}
+
+gboolean
+nm_device_needs_ip6_subnet (NMDevice *self)
+{
+ return NM_DEVICE_GET_PRIVATE (self)->needs_ip6_subnet;
+}
+
+/*
+ * Called on the ipv6.method=shared interface when a new subnet is allocated
+ * or the prefix from which it is allocated is renewed.
+ */
+void
+nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMPlatformIP6Address address = *subnet;
+
+ if (!priv->ac_ip6_config)
+ priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
+
+ /* Assign a ::1 address in the subnet for us. */
+ address.address.s6_addr32[3] |= htonl (1);
+ nm_ip6_config_add_address (priv->ac_ip6_config, &address);
+
+ _LOGD (LOGD_IP6, "ipv6-pd: using %s address",
+ nm_utils_inet6_ntop (&address.address, NULL));
+
+ /* This also updates the ndisc if there are actual changes. */
+ if (!ip6_config_merge_and_apply (self, TRUE, NULL))
+ _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing");
+}
+
+/*****************************************************************************/
+
static void
linklocal6_cleanup (NMDevice *self)
{
@@ -6066,6 +6138,12 @@ linklocal6_timeout_cb (gpointer user_data)
}
static void
+pd6_ask_for_prefix (NMDevice *self)
+{
+ g_signal_emit (self, signals[IP6_SUBNET_NEEDED], 0);
+}
+
+static void
linklocal6_complete (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@@ -6084,8 +6162,7 @@ linklocal6_complete (NMDevice *self)
_LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method);
- if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
- || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) {
+ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
if (!addrconf6_start_with_link_ready (self)) {
/* Time out IPv6 instead of failing the entire activation */
nm_device_activate_schedule_ip6_config_timeout (self);
@@ -6095,6 +6172,10 @@ linklocal6_complete (NMDevice *self)
/* Time out IPv6 instead of failing the entire activation */
nm_device_activate_schedule_ip6_config_timeout (self);
}
+ } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) {
+ priv->needs_ip6_subnet = TRUE;
+ pd6_ask_for_prefix (self);
+ nm_device_activate_schedule_ip6_config_timeout (self);
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0)
nm_device_activate_schedule_ip6_config_result (self);
else
@@ -6508,11 +6589,13 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
connection = nm_device_get_applied_connection (self);
g_assert (connection);
+#if 0
g_warn_if_fail (priv->ac_ip6_config == NULL);
if (priv->ac_ip6_config) {
g_object_unref (priv->ac_ip6_config);
priv->ac_ip6_config = NULL;
}
+#endif
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
g_assert (s_ip6);
@@ -6929,6 +7012,7 @@ nm_device_activate_stage3_ip6_start (NMDevice *self)
_set_ip_state (self, AF_INET6, IP_CONF);
ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
+#if 0
if (!ip6_config)
ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
/* Here we get a static IPv6 config, like for Shared where it's
@@ -6936,6 +7020,10 @@ nm_device_activate_stage3_ip6_start (NMDevice *self)
*/
g_warn_if_fail (priv->ac_ip6_config == NULL);
priv->ac_ip6_config = ip6_config;
+#else
+ if (!priv->ac_ip6_config)
+ priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
+#endif
nm_device_activate_schedule_ip6_config_result (self);
} else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) {
_set_ip_state (self, AF_INET6, IP_DONE);
@@ -10886,6 +10974,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
g_slist_free_full (priv->vpn6_configs, g_object_unref);
priv->vpn6_configs = NULL;
+ priv->needs_ip6_subnet = FALSE;
+
clear_act_request (self);
/* Clear legacy IPv4 address property */
@@ -13165,6 +13255,20 @@ nm_device_class_init (NMDeviceClass *klass)
0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
+ signals[IP6_PREFIX_DELEGATED] =
+ g_signal_new (NM_DEVICE_IP6_PREFIX_DELEGATED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+ signals[IP6_SUBNET_NEEDED] =
+ g_signal_new (NM_DEVICE_IP6_SUBNET_NEEDED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
signals[REMOVED] =
g_signal_new (NM_DEVICE_REMOVED,
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 356331189c..c1035a5b6c 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -82,6 +82,8 @@
#define NM_DEVICE_AUTH_REQUEST "auth-request"
#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed"
#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed"
+#define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated"
+#define NM_DEVICE_IP6_SUBNET_NEEDED "ip6-subnet-needed"
#define NM_DEVICE_REMOVED "removed"
#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate"
#define NM_DEVICE_RECHECK_ASSUME "recheck-assume"
@@ -439,6 +441,14 @@ void nm_device_set_enabled (NMDevice *device, gboolean enabled);
RfKillType nm_device_get_rfkill_type (NMDevice *device);
+/* IPv6 prefix delegation */
+
+void nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes);
+
+gboolean nm_device_needs_ip6_subnet (NMDevice *self);
+
+void nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet);
+
/**
* NMUnmanagedFlags:
* @NM_UNMANAGED_NONE: placeholder value