On Mon, Jul 29, 2024 at 3:01 PM Patrick Rohr <prohr@xxxxxxxxxx> wrote: > > draft-ietf-6man-pio-pflag is adding a new flag to the Prefix Information > Option to signal that the network can allocate a unique IPv6 prefix per > client via DHCPv6-PD (see draft-ietf-v6ops-dhcp-pd-per-device). > > When ra_honor_pio_pflag is enabled, the presence of a P-flag causes > SLAAC autoconfiguration to be disabled for that particular PIO. > > An automated test has been added in Android (r.android.com/3195335) to > go along with this change. > > Cc: Maciej Żenczykowski <maze@xxxxxxxxxx> > Cc: Lorenzo Colitti <lorenzo@xxxxxxxxxx> > Cc: David Lamparter <equinox@xxxxxxxxxxxxxxxxxxxxx> > Cc: Simon Horman <horms@xxxxxxxxxx> > Signed-off-by: Patrick Rohr <prohr@xxxxxxxxxx> > --- > Documentation/networking/ip-sysctl.rst | 14 ++++++++++++++ > include/linux/ipv6.h | 1 + > include/net/addrconf.h | 10 +++++++--- > net/ipv6/addrconf.c | 15 ++++++++++++++- > 4 files changed, 36 insertions(+), 4 deletions(-) > > diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst > index 3616389c8c2d..eacf8983e230 100644 > --- a/Documentation/networking/ip-sysctl.rst > +++ b/Documentation/networking/ip-sysctl.rst > @@ -2362,6 +2362,20 @@ ra_honor_pio_life - BOOLEAN > > Default: 0 (disabled) > > +ra_honor_pio_pflag - BOOLEAN > + The Prefix Information Option P-flag indicates the network can > + allocate a unique IPv6 prefix per client using DHCPv6-PD. > + This sysctl can be enabled when a userspace DHCPv6-PD client > + is running to cause the P-flag to take effect: i.e. the > + P-flag suppresses any effects of the A-flag within the same > + PIO. For a given PIO, P=1 and A=1 is treated as A=0. > + > + - If disabled, the P-flag is ignored. > + - If enabled, the P-flag will disable SLAAC autoconfiguration > + for the given Prefix Information Option. > + > + Default: 0 (disabled) > + > accept_ra_rt_info_min_plen - INTEGER > Minimum prefix length of Route Information in RA. > > diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h > index 383a0ea2ab91..a6e2aadbb91b 100644 > --- a/include/linux/ipv6.h > +++ b/include/linux/ipv6.h > @@ -89,6 +89,7 @@ struct ipv6_devconf { > __u8 ioam6_enabled; > __u8 ndisc_evict_nocarrier; > __u8 ra_honor_pio_life; > + __u8 ra_honor_pio_pflag; > > struct ctl_table_header *sysctl_header; > }; > diff --git a/include/net/addrconf.h b/include/net/addrconf.h > index 62a407db1bf5..b18e81f0c9e1 100644 > --- a/include/net/addrconf.h > +++ b/include/net/addrconf.h > @@ -37,10 +37,14 @@ struct prefix_info { > struct __packed { > #if defined(__BIG_ENDIAN_BITFIELD) > __u8 onlink : 1, > - autoconf : 1, > - reserved : 6; > + autoconf : 1, > + routeraddr : 1, > + preferpd : 1, > + reserved : 4; > #elif defined(__LITTLE_ENDIAN_BITFIELD) > - __u8 reserved : 6, > + __u8 reserved : 4, > + preferpd : 1, > + routeraddr : 1, > autoconf : 1, > onlink : 1; > #else > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c > index 55a0fd589fc8..4febf679a435 100644 > --- a/net/ipv6/addrconf.c > +++ b/net/ipv6/addrconf.c > @@ -239,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { > .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, > .ndisc_evict_nocarrier = 1, > .ra_honor_pio_life = 0, > + .ra_honor_pio_pflag = 0, > }; > > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { > @@ -302,6 +303,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { > .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE, > .ndisc_evict_nocarrier = 1, > .ra_honor_pio_life = 0, > + .ra_honor_pio_pflag = 0, > }; > > /* Check if link is ready: is it up and is a valid qdisc available */ > @@ -2762,6 +2764,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) > u32 addr_flags = 0; > struct inet6_dev *in6_dev; > struct net *net = dev_net(dev); > + bool ignore_autoconf = false; This ' = false' appears to be spurious (as ignore_autoconf is only read after being written), but is of course harmless. Reviewed-by: Maciej Żenczykowski <maze@xxxxxxxxxx> > pinfo = (struct prefix_info *) opt; > > @@ -2864,7 +2867,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) > > /* Try to figure out our local address for this prefix */ > > - if (pinfo->autoconf && in6_dev->cnf.autoconf) { > + ignore_autoconf = READ_ONCE(in6_dev->cnf.ra_honor_pio_pflag) && pinfo->preferpd; > + if (pinfo->autoconf && in6_dev->cnf.autoconf && !ignore_autoconf) { > struct in6_addr addr; > bool tokenized = false, dev_addr_generated = false; > > @@ -6926,6 +6930,15 @@ static const struct ctl_table addrconf_sysctl[] = { > .extra1 = SYSCTL_ZERO, > .extra2 = SYSCTL_ONE, > }, > + { > + .procname = "ra_honor_pio_pflag", > + .data = &ipv6_devconf.ra_honor_pio_pflag, > + .maxlen = sizeof(u8), > + .mode = 0644, > + .proc_handler = proc_dou8vec_minmax, > + .extra1 = SYSCTL_ZERO, > + .extra2 = SYSCTL_ONE, > + }, > #ifdef CONFIG_IPV6_ROUTER_PREF > { > .procname = "accept_ra_rtr_pref", > -- > 2.46.0.rc1.232.g9752f9e123-goog >