network: dhcp6: introduce UplinkInterface= for DHCP6 prefix delegation

This commit is contained in:
Yu Watanabe 2021-10-13 18:00:52 +09:00
parent 2cba2146ac
commit dc5cae6c9d
7 changed files with 64 additions and 1 deletions

View file

@ -2123,6 +2123,17 @@ Table=1234</programlisting></para>
is enabled.</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>UplinkInterface=</varname></term>
<listitem>
<para>Specifies the name or the index of the uplink interface, or one of the special values
<literal>:self</literal> and <literal>:auto</literal>. When <literal>:self</literal>, the
interface itself is considered the uplink interface. When <literal>:auto</literal>, the first
link which acquired prefixes to be delegated from the DHCPv6 server is selected. Defaults to
<literal>:auto</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SubnetId=</varname></term>
<listitem>

View file

@ -1281,6 +1281,7 @@ int config_parse_uplink(
void *userdata) {
Network *network = userdata;
bool accept_none = true;
int *index, r;
char **name;
@ -1288,6 +1289,7 @@ int config_parse_uplink(
assert(section);
assert(lvalue);
assert(rvalue);
assert(userdata);
if (streq(section, "DHCPServer")) {
index = &network->dhcp_server_uplink_index;
@ -1295,6 +1297,10 @@ int config_parse_uplink(
} else if (streq(section, "IPv6SendRA")) {
index = &network->router_uplink_index;
name = &network->router_uplink_name;
} else if (streq(section, "DHCPv6PrefixDelegation")) {
index = &network->dhcp6_pd_uplink_index;
name = &network->dhcp_server_uplink_name;
accept_none = false;
} else
assert_not_reached();
@ -1304,12 +1310,18 @@ int config_parse_uplink(
return 0;
}
if (streq(rvalue, ":none")) {
if (accept_none && streq(rvalue, ":none")) {
*index = UPLINK_INDEX_NONE;
*name = mfree(*name);
return 0;
}
if (!accept_none && streq(rvalue, ":self")) {
*index = UPLINK_INDEX_SELF;
*name = mfree(*name);
return 0;
}
r = parse_ifindex(rvalue);
if (r > 0) {
*index = r;

View file

@ -12,6 +12,7 @@
/* Special values for *_uplink_index. */
#define UPLINK_INDEX_AUTO 0 /* uplink will be selected automatically */
#define UPLINK_INDEX_NONE -1 /* uplink will not be selected automatically */
#define UPLINK_INDEX_SELF -2 /* the interface itself is uplink */
#define DHCP_ROUTE_METRIC 1024
#define DHCP6PD_ROUTE_METRIC 256

View file

@ -42,6 +42,22 @@ bool link_dhcp6_pd_is_enabled(Link *link) {
return link->network->dhcp6_pd;
}
static int dhcp6_pd_resolve_uplink(Link *link, Link **ret) {
if (link->network->dhcp6_pd_uplink_name)
return link_get_by_name(link->manager, link->network->dhcp6_pd_uplink_name, ret);
if (link->network->dhcp6_pd_uplink_index > 0)
return link_get_by_index(link->manager, link->network->dhcp6_pd_uplink_index, ret);
if (link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_SELF) {
*ret = link;
return 0;
}
assert(link->network->dhcp6_pd_uplink_index == UPLINK_INDEX_AUTO);
return -ENOENT;
}
static bool dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
uint32_t lifetime_preferred_sec, lifetime_valid_sec;
struct in6_addr pd_prefix;
@ -575,6 +591,7 @@ static int dhcp6_pd_distribute_prefix(
assert(pd_prefix_len <= 64);
HASHMAP_FOREACH(link, dhcp6_link->manager->links_by_index) {
Link *uplink;
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
continue;
@ -591,6 +608,15 @@ static int dhcp6_pd_distribute_prefix(
if (assign_preferred_subnet_id != link_has_preferred_subnet_id(link))
continue;
r = dhcp6_pd_resolve_uplink(link, &uplink);
if (r != -ENOENT) {
if (r < 0) /* The uplink interface does not exist yet. */
continue;
if (uplink != dhcp6_link)
continue;
}
r = dhcp6_pd_assign_prefix(link, pd_prefix, pd_prefix_len, lifetime_preferred_usec, lifetime_valid_usec);
if (r < 0) {
if (link == dhcp6_link)
@ -1402,8 +1428,17 @@ static int dhcp6_pd_find_uplink(Link *link, Link **ret) {
assert(link);
assert(link->manager);
assert(link->network);
assert(ret);
if (dhcp6_pd_resolve_uplink(link, &l) >= 0) {
if (!dhcp6_pd_uplink_is_ready(l))
return -EBUSY;
*ret = l;
return 0;
}
HASHMAP_FOREACH(l, link->manager->links_by_index) {
if (!dhcp6_pd_uplink_is_ready(l))
continue;

View file

@ -325,6 +325,7 @@ BridgeMDB.VLANId, config_parse_mdb_vlan_id,
BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
DHCPv6PrefixDelegation.UplinkInterface, config_parse_uplink, 0, 0
DHCPv6PrefixDelegation.SubnetId, config_parse_dhcp6_pd_subnet_id, 0, offsetof(Network, dhcp6_pd_subnet_id)
DHCPv6PrefixDelegation.Announce, config_parse_bool, 0, offsetof(Network, dhcp6_pd_announce)
DHCPv6PrefixDelegation.Assign, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign)

View file

@ -241,6 +241,8 @@ struct Network {
int64_t dhcp6_pd_subnet_id;
uint32_t dhcp6_pd_route_metric;
Set *dhcp6_pd_tokens;
int dhcp6_pd_uplink_index;
char *dhcp6_pd_uplink_name;
/* Bridge Support */
int use_bpdu;

View file

@ -151,6 +151,7 @@ DUIDType=
DUIDRawData=
RouteTable=
[DHCPv6PrefixDelegation]
UplinkInterface=
SubnetId=
Announce=
Assign=