mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-04-25 08:30:40 +02:00
dhcp-manager: add ability to specify the number of IPv6 prefixes to request
Utilizes RFC 3633 prefix option in role of requesting router to ask the delegating router for prefixes. In future we'll be able to use the addresses from those prefixes on ipv6.method=shared connections.
This commit is contained in:
parent
7d195856cc
commit
4ec37b0364
10 changed files with 117 additions and 28 deletions
|
|
@ -5992,7 +5992,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)),
|
||||
0);
|
||||
if (tmp)
|
||||
g_byte_array_free (tmp, TRUE);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
enum {
|
||||
SIGNAL_STATE_CHANGED,
|
||||
SIGNAL_PREFIX_DELEGATED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
|
@ -511,7 +512,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
const struct in6_addr *ll_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy)
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
NMDhcpClientPrivate *priv;
|
||||
gs_free char *str = NULL;
|
||||
|
|
@ -544,7 +546,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
ll_addr,
|
||||
info_only,
|
||||
privacy,
|
||||
priv->duid);
|
||||
priv->duid,
|
||||
needed_prefixes);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -709,6 +712,7 @@ nm_dhcp_client_handle_event (gpointer unused,
|
|||
guint32 new_state;
|
||||
GHashTable *str_options = NULL;
|
||||
GObject *ip_config = NULL;
|
||||
NMPlatformIP6Address prefix = { 0, };
|
||||
|
||||
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
|
||||
g_return_val_if_fail (iface != NULL, FALSE);
|
||||
|
|
@ -754,6 +758,7 @@ nm_dhcp_client_handle_event (gpointer unused,
|
|||
g_warn_if_fail (g_hash_table_size (str_options));
|
||||
if (g_hash_table_size (str_options)) {
|
||||
if (priv->ipv6) {
|
||||
prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options);
|
||||
ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex,
|
||||
priv->iface,
|
||||
str_options,
|
||||
|
|
@ -765,17 +770,26 @@ nm_dhcp_client_handle_event (gpointer unused,
|
|||
str_options,
|
||||
priv->priority);
|
||||
}
|
||||
|
||||
/* Fail if no valid IP config was received */
|
||||
if (ip_config == NULL) {
|
||||
_LOGW ("client bound but IP config not received");
|
||||
new_state = NM_DHCP_STATE_FAIL;
|
||||
g_clear_pointer (&str_options, g_hash_table_unref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nm_dhcp_client_set_state (self, new_state, ip_config, str_options);
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED (&prefix.address)) {
|
||||
/* If we got an IPv6 prefix to delegate, we don't change the state
|
||||
* of the DHCP client instance. Instead, we just signal the prefix
|
||||
* to the device. */
|
||||
g_signal_emit (G_OBJECT (self),
|
||||
signals[SIGNAL_PREFIX_DELEGATED], 0,
|
||||
&prefix);
|
||||
} else {
|
||||
/* Fail if no valid IP config was received */
|
||||
if (new_state == NM_DHCP_STATE_BOUND && ip_config == NULL) {
|
||||
_LOGW ("client bound but IP config not received");
|
||||
new_state = NM_DHCP_STATE_FAIL;
|
||||
g_clear_pointer (&str_options, g_hash_table_unref);
|
||||
}
|
||||
|
||||
nm_dhcp_client_set_state (self, new_state, ip_config, str_options);
|
||||
}
|
||||
|
||||
if (str_options)
|
||||
g_hash_table_destroy (str_options);
|
||||
|
|
@ -972,5 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
|
|||
G_STRUCT_OFFSET (NMDhcpClientClass, state_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING);
|
||||
}
|
||||
|
||||
signals[SIGNAL_PREFIX_DELEGATED] =
|
||||
g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMDhcpClientClass, state_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
|
||||
|
||||
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
|
||||
#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
|
||||
|
||||
typedef enum {
|
||||
NM_DHCP_STATE_UNKNOWN = 0,
|
||||
|
|
@ -73,7 +74,8 @@ typedef struct {
|
|||
const struct in6_addr *ll_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid);
|
||||
const GByteArray *duid,
|
||||
guint needed_prefixes);
|
||||
|
||||
void (*stop) (NMDhcpClient *self,
|
||||
gboolean release,
|
||||
|
|
@ -133,7 +135,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
|
|||
const struct in6_addr *ll_addr,
|
||||
const char *hostname,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy);
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
guint needed_prefixes);
|
||||
|
||||
void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release);
|
||||
|
||||
|
|
|
|||
|
|
@ -330,7 +330,8 @@ dhclient_start (NMDhcpClient *client,
|
|||
const char *mode_opt,
|
||||
const GByteArray *duid,
|
||||
gboolean release,
|
||||
pid_t *out_pid)
|
||||
pid_t *out_pid,
|
||||
int prefixes)
|
||||
{
|
||||
NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
|
||||
|
|
@ -424,6 +425,8 @@ dhclient_start (NMDhcpClient *client,
|
|||
g_ptr_array_add (argv, (gpointer) "-6");
|
||||
if (mode_opt)
|
||||
g_ptr_array_add (argv, (gpointer) mode_opt);
|
||||
while (prefixes--)
|
||||
g_ptr_array_add (argv, (gpointer) "-P");
|
||||
}
|
||||
g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */
|
||||
g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
|
||||
|
|
@ -503,7 +506,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
|
|||
if (priv->conf_file) {
|
||||
if (new_client_id)
|
||||
nm_dhcp_client_set_client_id (client, new_client_id);
|
||||
success = dhclient_start (client, NULL, NULL, FALSE, NULL);
|
||||
success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0);
|
||||
} else
|
||||
_LOGW ("error creating dhclient configuration file");
|
||||
|
||||
|
|
@ -516,7 +519,8 @@ ip6_start (NMDhcpClient *client,
|
|||
const struct in6_addr *ll_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
const GByteArray *duid,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
|
||||
|
|
@ -532,7 +536,7 @@ ip6_start (NMDhcpClient *client,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL);
|
||||
return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -557,7 +561,7 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
|
|||
if (release) {
|
||||
pid_t rpid = -1;
|
||||
|
||||
if (dhclient_start (client, NULL, duid, TRUE, &rpid)) {
|
||||
if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) {
|
||||
/* Wait a few seconds for the release to happen */
|
||||
nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,8 @@ ip6_start (NMDhcpClient *client,
|
|||
const struct in6_addr *ll_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
const GByteArray *duid,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client);
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,8 @@ client_start (NMDhcpManager *self,
|
|||
const char *fqdn,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const char *last_ip4_address)
|
||||
const char *last_ip4_address,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
NMDhcpManagerPrivate *priv;
|
||||
NMDhcpClient *client;
|
||||
|
|
@ -206,7 +207,7 @@ client_start (NMDhcpManager *self,
|
|||
g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
|
||||
|
||||
if (ipv6)
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy);
|
||||
success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes);
|
||||
else
|
||||
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address);
|
||||
|
||||
|
|
@ -254,7 +255,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
|
|||
}
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL,
|
||||
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
|
||||
fqdn, FALSE, 0, last_ip_address);
|
||||
fqdn, FALSE, 0, last_ip_address, 0);
|
||||
}
|
||||
|
||||
/* Caller owns a reference to the NMDhcpClient on return */
|
||||
|
|
@ -271,7 +272,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy)
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
|
||||
|
|
@ -281,7 +283,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|||
hostname = get_send_hostname (self, dhcp_hostname);
|
||||
return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE,
|
||||
ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only,
|
||||
privacy, NULL);
|
||||
privacy, NULL, needed_prefixes);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
|
|||
guint32 timeout,
|
||||
const char *dhcp_anycast_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy);
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
guint needed_prefixes);
|
||||
|
||||
GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
|
||||
const char *iface,
|
||||
|
|
|
|||
|
|
@ -894,7 +894,8 @@ ip6_start (NMDhcpClient *client,
|
|||
const struct in6_addr *ll_addr,
|
||||
gboolean info_only,
|
||||
NMSettingIP6ConfigPrivacy privacy,
|
||||
const GByteArray *duid)
|
||||
const GByteArray *duid,
|
||||
guint needed_prefixes)
|
||||
{
|
||||
NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
|
||||
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
|
||||
|
|
@ -916,7 +917,12 @@ ip6_start (NMDhcpClient *client,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
_LOGT ("dhcp-client6: set %p", priv->client4);
|
||||
if (needed_prefixes > 0) {
|
||||
_LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes\n",
|
||||
needed_prefixes);
|
||||
}
|
||||
|
||||
_LOGT ("dhcp-client6: set %p", priv->client6);
|
||||
|
||||
if (info_only)
|
||||
sd_dhcp6_client_set_information_request (priv->client6, 1);
|
||||
|
|
|
|||
|
|
@ -604,6 +604,54 @@ ip6_add_domain_search (gpointer data, gpointer user_data)
|
|||
nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data);
|
||||
}
|
||||
|
||||
NMPlatformIP6Address
|
||||
nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options)
|
||||
{
|
||||
gs_strfreev gchar **split_addr = NULL;
|
||||
NMPlatformIP6Address address = { 0, };
|
||||
struct in6_addr tmp_addr;
|
||||
char *str = NULL;
|
||||
int prefix;
|
||||
|
||||
g_return_val_if_fail (options != NULL, address);
|
||||
|
||||
str = g_hash_table_lookup (options, "ip6_prefix");
|
||||
if (!str)
|
||||
return address;
|
||||
|
||||
split_addr = g_strsplit (str, "/", 2);
|
||||
if (split_addr[0] == NULL && split_addr[1] == NULL) {
|
||||
nm_log_warn (LOGD_DHCP6, "DHCP returned prefix without length '%s'", str);
|
||||
return address;
|
||||
}
|
||||
|
||||
if (!inet_pton (AF_INET6, split_addr[0], &tmp_addr)) {
|
||||
nm_log_warn (LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str);
|
||||
return address;
|
||||
}
|
||||
|
||||
prefix = _nm_utils_ascii_str_to_int64 (split_addr[1], 10, 0, 128, -1);
|
||||
if (prefix < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str);
|
||||
return address;
|
||||
}
|
||||
|
||||
address.address = tmp_addr;
|
||||
address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
|
||||
address.plen = prefix;
|
||||
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
str = g_hash_table_lookup (options, "max_life");
|
||||
if (str)
|
||||
address.lifetime = strtoul (str, NULL, 10);
|
||||
|
||||
str = g_hash_table_lookup (options, "preferred_life");
|
||||
if (str)
|
||||
address.preferred = strtoul (str, NULL, 10);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
NMIP6Config *
|
||||
nm_dhcp_utils_ip6_config_from_options (int ifindex,
|
||||
const char *iface,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex,
|
|||
guint priority,
|
||||
gboolean info_only);
|
||||
|
||||
NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options);
|
||||
|
||||
char * nm_dhcp_utils_duid_to_string (const GByteArray *duid);
|
||||
|
||||
GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue