mirror of
https://github.com/systemd/systemd.git
synced 2025-01-10 05:18:17 +03:00
Merge pull request #9981 from pfl/dhcp6_pd_other_information_quirk
DHCPv6 PD other information quirk
This commit is contained in:
commit
54e6f0a38f
@ -1372,6 +1372,22 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
|
||||
<listitem>
|
||||
<para>A boolean that enforces DHCPv6 stateful mode when the 'Other information' bit is set in
|
||||
Router Advertisement messages. By default setting only the 'O' bit in Router Advertisements
|
||||
makes DHCPv6 request network information in a stateless manner using a two-message Information
|
||||
Request and Information Reply message exchange.
|
||||
<ulink url="https://tools.ietf.org/html/rfc7084">RFC 7084</ulink>, requirement WPD-4, updates
|
||||
this behavior for a Customer Edge router so that stateful DHCPv6 Prefix Delegation is also
|
||||
requested when only the 'O' bit is set in Router Advertisements. This option enables such a CE
|
||||
behavior as it is impossible to automatically distinguish the intention of the 'O' bit otherwise.
|
||||
By default this option is set to 'false', enable it if no prefixes are delegated when the device
|
||||
should be acting as a CE router.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -73,8 +73,6 @@ struct DHCP6IA {
|
||||
struct ia_pd ia_pd;
|
||||
struct ia_ta ia_ta;
|
||||
};
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
|
||||
LIST_HEAD(DHCP6Address, addresses);
|
||||
};
|
||||
|
@ -37,7 +37,6 @@ struct sd_dhcp6_lease {
|
||||
size_t ntp_fqdn_count;
|
||||
};
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia);
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
||||
|
||||
@ -50,6 +49,7 @@ int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
|
||||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
|
||||
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
||||
|
@ -27,6 +27,13 @@
|
||||
|
||||
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
||||
|
||||
/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
|
||||
enum {
|
||||
DHCP6_REQUEST_IA_NA = 1,
|
||||
DHCP6_REQUEST_IA_TA = 2, /* currently not used */
|
||||
DHCP6_REQUEST_IA_PD = 4,
|
||||
};
|
||||
|
||||
struct sd_dhcp6_client {
|
||||
unsigned n_ref;
|
||||
|
||||
@ -40,7 +47,9 @@ struct sd_dhcp6_client {
|
||||
uint16_t arp_type;
|
||||
DHCP6IA ia_na;
|
||||
DHCP6IA ia_pd;
|
||||
bool prefix_delegation;
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
int request;
|
||||
be32_t transaction_id;
|
||||
usec_t transaction_start;
|
||||
struct sd_dhcp6_lease *lease;
|
||||
@ -325,10 +334,36 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) {
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(delegation, -EINVAL);
|
||||
|
||||
*delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->prefix_delegation = delegation;
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(request, -EINVAL);
|
||||
|
||||
*request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -355,12 +390,8 @@ static void client_notify(sd_dhcp6_client *client, int event) {
|
||||
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
||||
assert(client);
|
||||
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
|
||||
client->lease = lease;
|
||||
(void) sd_dhcp6_lease_unref(client->lease);
|
||||
client->lease = sd_dhcp6_lease_ref(lease);
|
||||
}
|
||||
|
||||
static int client_reset(sd_dhcp6_client *client) {
|
||||
@ -374,11 +405,6 @@ static int client_reset(sd_dhcp6_client *client) {
|
||||
client->transaction_id = 0;
|
||||
client->transaction_start = 0;
|
||||
|
||||
client->ia_na.timeout_t1 =
|
||||
sd_event_source_unref(client->ia_na.timeout_t1);
|
||||
client->ia_na.timeout_t2 =
|
||||
sd_event_source_unref(client->ia_na.timeout_t2);
|
||||
|
||||
client->retransmit_time = 0;
|
||||
client->retransmit_count = 0;
|
||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
@ -436,9 +462,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->ia_na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
@ -446,7 +475,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -471,9 +500,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
@ -481,7 +513,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -495,9 +527,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
case DHCP6_STATE_REBIND:
|
||||
message->type = DHCP6_REBIND;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
@ -505,7 +539,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -562,8 +596,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t2 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t2);
|
||||
client->timeout_t2 =
|
||||
sd_event_source_unref(client->timeout_t2);
|
||||
|
||||
log_dhcp6_client(client, "Timeout T2");
|
||||
|
||||
@ -579,8 +613,8 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t1 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t1);
|
||||
client->timeout_t1 =
|
||||
sd_event_source_unref(client->timeout_t1);
|
||||
|
||||
log_dhcp6_client(client, "Timeout T1");
|
||||
|
||||
@ -914,7 +948,7 @@ static int client_parse_message(
|
||||
if (r < 0 && r != -ENOMSG)
|
||||
return r;
|
||||
|
||||
r = dhcp6_lease_get_iaid(lease, &iaid_lease);
|
||||
r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1188,10 +1222,33 @@ static int client_receive_message(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
||||
uint32_t *lifetime_t2) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||
int r;
|
||||
usec_t timeout, time_now;
|
||||
char time_string[FORMAT_TIMESPAN_MAX];
|
||||
uint32_t lifetime_t1, lifetime_t2;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
@ -1251,57 +1308,58 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||
|
||||
case DHCP6_STATE_BOUND:
|
||||
|
||||
if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
|
||||
client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
|
||||
r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
|
||||
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
|
||||
be32toh(client->lease->ia.ia_na.lifetime_t1),
|
||||
be32toh(client->lease->ia.ia_na.lifetime_t2));
|
||||
lifetime_t1, lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
|
||||
|
||||
log_dhcp6_client(client, "T1 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&client->lease->ia.timeout_t1,
|
||||
&client->timeout_t1,
|
||||
clock_boottime_or_monotonic(), time_now + timeout,
|
||||
10 * USEC_PER_SEC, client_timeout_t1,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
|
||||
r = sd_event_source_set_priority(client->timeout_t1,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
|
||||
r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
|
||||
|
||||
log_dhcp6_client(client, "T2 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&client->lease->ia.timeout_t2,
|
||||
&client->timeout_t2,
|
||||
clock_boottime_or_monotonic(), time_now + timeout,
|
||||
10 * USEC_PER_SEC, client_timeout_t2,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
|
||||
r = sd_event_source_set_priority(client->timeout_t2,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
|
||||
r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
@ -1363,6 +1421,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
||||
return -EBUSY;
|
||||
|
||||
if (!client->information_request && !client->request)
|
||||
return -EINVAL;
|
||||
|
||||
r = client_reset(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1461,6 +1522,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
||||
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
|
||||
client->ifindex = -1;
|
||||
client->request = DHCP6_REQUEST_IA_NA;
|
||||
client->fd = -1;
|
||||
|
||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
||||
|
@ -11,15 +11,6 @@
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
|
||||
assert_return(ia, -EINVAL);
|
||||
|
||||
ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
|
||||
ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||
DHCP6Address *addr;
|
||||
uint32_t valid = 0, t;
|
||||
@ -48,8 +39,6 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
|
||||
if (!ia)
|
||||
return NULL;
|
||||
|
||||
dhcp6_lease_clear_timers(ia);
|
||||
|
||||
while (ia->addresses) {
|
||||
address = ia->addresses;
|
||||
|
||||
@ -136,6 +125,15 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
||||
*iaid = lease->pd.ia_pd.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
|
@ -37,6 +37,7 @@ static uint8_t test_duid[14] = { };
|
||||
|
||||
static int test_client_basic(sd_event *e) {
|
||||
sd_dhcp6_client *client;
|
||||
int v;
|
||||
|
||||
if (verbose)
|
||||
printf("* %s\n", __FUNCTION__);
|
||||
@ -68,6 +69,36 @@ static int test_client_basic(sd_event *e) {
|
||||
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
|
||||
assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
|
||||
v = 0;
|
||||
assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
assert_se(sd_dhcp6_client_set_information_request(client, 0) >= 0);
|
||||
v = 42;
|
||||
assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
|
||||
assert_se(v == 0);
|
||||
|
||||
v = 0;
|
||||
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
v = 0;
|
||||
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
v = 42;
|
||||
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||
assert_se(sd_dhcp6_client_set_prefix_delegation(client, 1) >= 0);
|
||||
v = 0;
|
||||
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
v = 0;
|
||||
assert_se(sd_dhcp6_client_get_prefix_delegation(client, &v) >= 0);
|
||||
assert_se(v);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
|
||||
|
||||
assert_se(sd_dhcp6_client_detach_event(client) >= 0);
|
||||
@ -862,7 +893,7 @@ static int test_client_solicit(sd_event *e) {
|
||||
sd_dhcp6_client *client;
|
||||
usec_t time_now = now(clock_boottime_or_monotonic());
|
||||
struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
|
||||
int val = true;
|
||||
int val;
|
||||
|
||||
if (verbose)
|
||||
printf("* %s\n", __FUNCTION__);
|
||||
@ -879,10 +910,10 @@ static int test_client_solicit(sd_event *e) {
|
||||
assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
|
||||
|
||||
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
||||
assert_se(val == false);
|
||||
assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
|
||||
assert_se(val == 0);
|
||||
assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
|
||||
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
||||
assert_se(val == true);
|
||||
assert_se(val);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_callback(client,
|
||||
test_client_information_cb, e) >= 0);
|
||||
|
@ -103,12 +103,77 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
|
||||
return sd_radv_start(radv);
|
||||
}
|
||||
|
||||
static Network *dhcp6_reset_pd_prefix_network(Link *link) {
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->manager->networks);
|
||||
static int dhcp6_route_remove_cb(sd_netlink *nl, sd_netlink_message *m,
|
||||
void *userdata) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
|
||||
return link->manager->networks;
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(l, r, "Received error on unreachable route removal for DHCPv6 delegated subnetl: %m");
|
||||
|
||||
l = link_unref(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
|
||||
int r;
|
||||
sd_dhcp6_lease *lease;
|
||||
union in_addr_union pd_prefix;
|
||||
uint8_t pd_prefix_len;
|
||||
uint32_t lifetime_preferred, lifetime_valid;
|
||||
|
||||
r = sd_dhcp6_client_get_lease(client, &lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||
|
||||
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
_cleanup_free_ Route *route;
|
||||
|
||||
if (pd_prefix_len > 64)
|
||||
continue;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||
|
||||
if (pd_prefix_len < 64) {
|
||||
r = route_new(&route);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
|
||||
0, 0, 0, &route);
|
||||
route_update(route, NULL, 0, NULL, NULL, 0, 0,
|
||||
RTN_UNREACHABLE);
|
||||
|
||||
r = route_remove(route, link, dhcp6_route_remove_cb);
|
||||
if (r < 0) {
|
||||
(void) in_addr_to_string(AF_INET6,
|
||||
&pd_prefix, &buf);
|
||||
|
||||
log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
route_free(route);
|
||||
continue;
|
||||
}
|
||||
link = link_ref(link);
|
||||
|
||||
log_link_debug(link, "Removing unreachable route %s/%u",
|
||||
strnull(buf), pd_prefix_len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
|
||||
@ -184,39 +249,28 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
|
||||
return r;
|
||||
}
|
||||
|
||||
if (n_used < n_prefixes) {
|
||||
Route *route;
|
||||
uint64_t n = n_used;
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
route->family = AF_INET6;
|
||||
|
||||
while (n < n_prefixes) {
|
||||
route_update(route, &prefix, pd_prefix_len, NULL, NULL,
|
||||
0, 0, RTN_UNREACHABLE);
|
||||
|
||||
r = route_configure(route, dhcp6_link, NULL);
|
||||
if (r < 0) {
|
||||
route_free(route);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = in_addr_prefix_next(AF_INET6, &prefix, pd_prefix_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return n_used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp6_route_add_cb(sd_netlink *nl, sd_netlink_message *m,
|
||||
void *userdata) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_debug_errno(l, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
|
||||
|
||||
l = link_unref(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
||||
int r;
|
||||
sd_dhcp6_lease *lease;
|
||||
struct in6_addr pd_prefix;
|
||||
union in_addr_union pd_prefix;
|
||||
uint8_t pd_prefix_len;
|
||||
uint32_t lifetime_preferred, lifetime_valid;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
@ -226,27 +280,62 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
dhcp6_reset_pd_prefix_network(link);
|
||||
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||
|
||||
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len,
|
||||
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
|
||||
&lifetime_preferred,
|
||||
&lifetime_valid) >= 0) {
|
||||
|
||||
if (pd_prefix_len > 64) {
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
|
||||
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
|
||||
strnull(buf), pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pd_prefix_len < 48) {
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
|
||||
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
|
||||
strnull(buf), pd_prefix_len);
|
||||
}
|
||||
|
||||
r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix,
|
||||
if (pd_prefix_len < 64) {
|
||||
Route *route = NULL;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
|
||||
0, 0, 0, &route);
|
||||
route_update(route, NULL, 0, NULL, NULL, 0, 0,
|
||||
RTN_UNREACHABLE);
|
||||
|
||||
r = route_configure(route, link, dhcp6_route_add_cb);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
|
||||
strnull(buf),
|
||||
pd_prefix_len);
|
||||
route_free(route);
|
||||
continue;
|
||||
}
|
||||
link = link_ref(link);
|
||||
|
||||
route_free(route);
|
||||
|
||||
log_link_debug(link, "Configuring unreachable route for %s/%u",
|
||||
strnull(buf), pd_prefix_len);
|
||||
|
||||
} else
|
||||
log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
|
||||
|
||||
r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix.in6,
|
||||
pd_prefix_len,
|
||||
lifetime_preferred,
|
||||
lifetime_valid);
|
||||
@ -364,6 +453,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
||||
if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
|
||||
log_link_warning(link, "DHCPv6 lease lost");
|
||||
|
||||
(void) dhcp6_lease_pd_prefix_lost(client, link);
|
||||
(void) manager_dhcp6_prefix_remove_all(link->manager, link);
|
||||
|
||||
link->dhcp6_configured = false;
|
||||
@ -403,11 +493,12 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
||||
}
|
||||
|
||||
int dhcp6_request_address(Link *link, int ir) {
|
||||
int r, inf_req;
|
||||
int r, inf_req, pd;
|
||||
bool running;
|
||||
|
||||
assert(link);
|
||||
assert(link->dhcp6_client);
|
||||
assert(link->network);
|
||||
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
||||
|
||||
r = sd_dhcp6_client_is_running(link->dhcp6_client);
|
||||
@ -416,6 +507,21 @@ int dhcp6_request_address(Link *link, int ir) {
|
||||
else
|
||||
running = r;
|
||||
|
||||
r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (pd && ir && link->network->dhcp6_force_pd_other_information) {
|
||||
log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
|
||||
|
||||
r = sd_dhcp6_client_set_address_request(link->dhcp6_client,
|
||||
false);
|
||||
if (r < 0 )
|
||||
return r;
|
||||
|
||||
ir = false;
|
||||
}
|
||||
|
||||
if (running) {
|
||||
r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
|
||||
if (r < 0)
|
||||
|
@ -165,6 +165,7 @@ int dhcp4_set_client_identifier(Link *link);
|
||||
int dhcp4_set_promote_secondaries(Link *link);
|
||||
int dhcp6_configure(Link *link);
|
||||
int dhcp6_request_address(Link *link, int ir);
|
||||
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
|
||||
|
||||
const char* link_state_to_string(LinkState s) _const_;
|
||||
LinkState link_state_from_string(const char *s) _pure_;
|
||||
|
@ -1240,27 +1240,15 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
|
||||
}
|
||||
|
||||
static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||
void *userdata) {
|
||||
void *userdata) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
union in_addr_union prefix;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r != 0) {
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
||||
log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64",
|
||||
strnull(buf));
|
||||
l = link_unref(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1268,6 +1256,7 @@ static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
||||
int r;
|
||||
Route *route;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->dhcp6_prefixes, -ENODATA);
|
||||
@ -1282,6 +1271,11 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
|
||||
log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
|
||||
|
||||
link = link_ref(link);
|
||||
|
||||
return hashmap_put(m->dhcp6_prefixes, addr, link);
|
||||
}
|
||||
|
||||
@ -1289,24 +1283,12 @@ static int dhcp6_route_remove_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||
void *userdata) {
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
union in_addr_union prefix;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r != 0) {
|
||||
if (r < 0)
|
||||
log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
||||
log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64",
|
||||
strnull(buf));
|
||||
l = link_unref(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1315,6 +1297,7 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||
Link *l;
|
||||
int r;
|
||||
Route *route;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(m->dhcp6_prefixes, -ENODATA);
|
||||
@ -1327,8 +1310,17 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||
(void) sd_radv_remove_prefix(l->radv, addr, 64);
|
||||
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
|
||||
0, 0, 0, &route);
|
||||
if (r >= 0)
|
||||
(void) route_remove(route, l, dhcp6_route_remove_callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = route_remove(route, l, dhcp6_route_remove_callback);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
|
||||
log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
|
||||
|
||||
l = link_ref(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1452,11 +1444,18 @@ void manager_free(Manager *m) {
|
||||
network_free(network);
|
||||
|
||||
while ((link = hashmap_first(m->dhcp6_prefixes)))
|
||||
link_unref(link);
|
||||
manager_dhcp6_prefix_remove_all(m, link);
|
||||
hashmap_free(m->dhcp6_prefixes);
|
||||
|
||||
while ((link = hashmap_first(m->links)))
|
||||
while ((link = hashmap_first(m->links))) {
|
||||
if (link->dhcp6_client)
|
||||
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client,
|
||||
link);
|
||||
|
||||
hashmap_remove(m->links, INT_TO_PTR(link->ifindex));
|
||||
|
||||
link_unref(link);
|
||||
}
|
||||
hashmap_free(m->links);
|
||||
|
||||
set_free(m->links_requesting_uuid);
|
||||
|
@ -138,6 +138,7 @@ DHCP.UseTimezone, config_parse_bool,
|
||||
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
|
||||
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
|
||||
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
|
||||
DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
|
||||
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
|
||||
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
||||
IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table)
|
||||
|
@ -171,6 +171,9 @@ struct Network {
|
||||
struct in6_addr *router_dns;
|
||||
unsigned n_router_dns;
|
||||
char **router_search_domains;
|
||||
bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
|
||||
RA flag is set, see RFC 7084,
|
||||
WPD-4 */
|
||||
|
||||
/* Bridge Support */
|
||||
int use_bpdu;
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
@ -120,8 +119,14 @@ int sd_dhcp6_client_get_information_request(
|
||||
int sd_dhcp6_client_set_request_option(
|
||||
sd_dhcp6_client *client,
|
||||
uint16_t option);
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
|
||||
int *delegation);
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
|
||||
bool delegation);
|
||||
int delegation);
|
||||
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client,
|
||||
int *request);
|
||||
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
|
||||
int request);
|
||||
|
||||
int sd_dhcp6_client_get_lease(
|
||||
sd_dhcp6_client *client,
|
||||
|
Loading…
Reference in New Issue
Block a user