From: Paul Donald Date: Sun, 9 Nov 2025 23:00:05 +0000 (+0100) Subject: odhcpd: Implement RFC9762 DHCPv6 PD Preferred flag for PIOs X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=a89b57fa1786692416558c54746802618f3f8c8f;p=project%2Fodhcpd.git odhcpd: Implement RFC9762 DHCPv6 PD Preferred flag for PIOs The RFC defines the P flag for use within PIOs, and defines its meaning as "purely a positive indicator, telling nodes that DHCPv6 PD is available and the network prefers that nodes use it". The RFC abstract lays out: The (P) flag is used to indicate that the network prefers that clients use the deployment model in RFC 9663 instead of using individual addresses in the on-link prefix assigned using SLAAC, or DHCPv6 address assignment. Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcpd/pull/301 Signed-off-by: Álvaro Fernández Rojas --- diff --git a/README.md b/README.md index 7f3d347..c9ac2ec 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,8 @@ and may also receive information from ubus | dhcpv6_assignall |bool | 1 | Assign all viable DHCPv6 addresses in statefull mode; if disabled only the DHCPv6 address having the longest preferred lifetime is assigned | | dhcpv6_hostidlength |integer| 12 | Host ID length of dynamically created leases, allowed values: 12 - 64 (bits). | | dhcpv6_na |bool | 1 | DHCPv6 stateful addressing hands out IA_NA - Internet Address - Network Address | -| dhcpv6_pd |bool | 1 | DHCPv6 stateful addressing hands out IA_PD - Internet Address - Prefix Delegation | +| dhcpv6_pd |bool | 1 | DHCPv6 stateful addressing hands out IA_PD - Internet Address - Prefix Delegation (PD) | +| dhcpv6_pd_preferred |bool | 0 | Set the DHCPv6-PD Preferred (P) flag in outgoing ICMPv6 RA message PIOs (RFC9762); requires `dhcpv6` and `dhcpv6_pd`. | | dhcpv6_pd_min_len |integer| - | Minimum prefix length to delegate with IA_PD (value is adjusted if needed to be greater than the interface prefix length). Range [1,62] | | router |list |``| Routers to announce, accepts IPv4 only | | dns |list |``| DNS servers to announce, accepts IPv4 and IPv6 | diff --git a/src/config.c b/src/config.c index 1821b52..109376a 100644 --- a/src/config.c +++ b/src/config.c @@ -106,6 +106,7 @@ enum { IFACE_ATTR_DHCPV4_FORCERECONF, IFACE_ATTR_DHCPV6_RAW, IFACE_ATTR_DHCPV6_ASSIGNALL, + IFACE_ATTR_DHCPV6_PD_PREFERRED, IFACE_ATTR_DHCPV6_PD, IFACE_ATTR_DHCPV6_PD_MIN_LEN, IFACE_ATTR_DHCPV6_NA, @@ -157,6 +158,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_DHCPV4_FORCERECONF] = { .name = "dhcpv4_forcereconf", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_DHCPV6_PD_PREFERRED] = { .name = "dhcpv6_pd_preferred", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_PD] = { .name = "dhcpv6_pd", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DHCPV6_PD_MIN_LEN] = { .name = "dhcpv6_pd_min_len", .type = BLOBMSG_TYPE_INT32 }, [IFACE_ATTR_DHCPV6_NA] = { .name = "dhcpv6_na", .type = BLOBMSG_TYPE_BOOL }, @@ -311,6 +313,7 @@ static void set_interface_defaults(struct interface *iface) iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1); iface->dhcpv6_assignall = true; iface->dhcpv6_pd = true; + iface->dhcpv6_pd_preferred = false; iface->dhcpv6_pd_min_len = 0; iface->dhcpv6_na = true; iface->dhcpv6_hostid_len = HOSTID_LEN_DEFAULT; @@ -1378,6 +1381,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if ((c = tb[IFACE_ATTR_DHCPV6_ASSIGNALL])) iface->dhcpv6_assignall = blobmsg_get_bool(c); + if ((c = tb[IFACE_ATTR_DHCPV6_PD_PREFERRED])) + iface->dhcpv6_pd_preferred = blobmsg_get_bool(c); + if ((c = tb[IFACE_ATTR_DHCPV6_PD])) iface->dhcpv6_pd = blobmsg_get_bool(c); diff --git a/src/odhcpd.h b/src/odhcpd.h index 23f82d8..6cae39d 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -440,6 +440,7 @@ struct interface { size_t dhcpv6_raw_len; bool dhcpv6_assignall; bool dhcpv6_pd; + bool dhcpv6_pd_preferred; bool dhcpv6_na; uint32_t dhcpv6_hostid_len; uint32_t dhcpv6_pd_min_len; // minimum delegated prefix length diff --git a/src/router.c b/src/router.c index 9b8d002..1903eb4 100644 --- a/src/router.c +++ b/src/router.c @@ -591,6 +591,15 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr adv.h.nd_ra_flags_reserved |= ND_RA_PREF_LOW; else if (iface->route_preference > 0) adv.h.nd_ra_flags_reserved |= ND_RA_PREF_HIGH; + + if (iface->dhcpv6 != MODE_DISABLED && iface->dhcpv6_pd && iface->dhcpv6_pd_preferred) { + /* RFC9762 § 5 + * If the network desires to delegate prefixes to devices that support + * DHCPv6 prefix delegation but do not support the P flag, it SHOULD + * also set the M or O bits in the RA to 1 + */ + adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; + } adv.h.nd_ra_reachable = htonl(iface->ra_reachabletime); adv.h.nd_ra_retransmit = htonl(iface->ra_retranstime); @@ -737,11 +746,23 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; p->nd_opt_pi_len = 4; p->nd_opt_pi_prefix_len = (addr->prefix < 64) ? 64 : addr->prefix; + /* RFC9762 DHCPv6-PD Preferred Flag § 6: + * Routers SHOULD set the P flag to zero by default... + */ p->nd_opt_pi_flags_reserved = 0; if (!iface->ra_not_onlink) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; if (iface->ra_slaac && addr->prefix <= 64) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; + if (iface->dhcpv6 != MODE_DISABLED && iface->dhcpv6_pd && iface->dhcpv6_pd_preferred) + /* RFC9762 DHCPv6-PD Preferred Flag + * We can run both SLAAC and DHCPv6-PD. + * §6: + * "Routers MUST allow the P flag to be configured separately from the A flag. + * ...en/disabling the P flag MUST NOT trigger automatic changes in the A flag + * value set by the router." + */ + p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_PD_PREFERRED; if (iface->ra_advrouter) // RFC6275, §7.2 p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; diff --git a/src/router.h b/src/router.h index afcf3df..46c6387 100644 --- a/src/router.h +++ b/src/router.h @@ -93,3 +93,8 @@ struct icmpv6_opt { #define ND_RA_FLAG_PROXY 0x4 #define ND_RA_PREF_HIGH (1 << 3) #define ND_RA_PREF_LOW (3 << 3) + +/* RFC9762 DHCPv6 PD Availability - Preferred Flag + * use this until it is defined in netinet/icmp6.h + */ +#define ND_OPT_PI_FLAG_PD_PREFERRED 0x10