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>
void *userdata) {
Network *network = userdata;
+ bool accept_none = true;
int *index, r;
char **name;
assert(section);
assert(lvalue);
assert(rvalue);
+ assert(userdata);
if (streq(section, "DHCPServer")) {
index = &network->dhcp_server_uplink_index;
} 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();
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;
/* 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
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;
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;
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)
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;
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)
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;
DUIDRawData=
RouteTable=
[DHCPv6PrefixDelegation]
+UplinkInterface=
SubnetId=
Announce=
Assign=