Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
[not found] <175b25d0c79.f8ce5734515834.1635475016968827598@shytyi.net>
@ 2020-11-10 17:45 ` Dmytro Shytyi
2020-11-11 1:34 ` kernel test robot
0 siblings, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-10 17:45 UTC (permalink / raw)
To: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-v2-5.10.0-rc2/include/net/if_inet6.h
--- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
+++ net-next-patch-v2-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 12:43:26.866166351 +0100
@@ -22,6 +22,12 @@
#define IF_RS_SENT 0x10
#define IF_READY 0x80000000
+/* Variable SLAAC (Contact: Dmytro Shytyi)
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+#define IF_RA_VAR_PLEN 0x08
+
/* prefix flags */
#define IF_PREFIX_ONLINK 0x01
#define IF_PREFIX_AUTOCONF 0x02
diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-v2-5.10.0-rc2/include/uapi/linux/icmpv6.h
--- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
+++ net-next-patch-v2-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 12:43:26.866166351 +0100
@@ -42,7 +42,9 @@ struct icmp6hdr {
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:3,
+ __u8 reserved:1,
+ slaac_var_plen:1,
+ proxy:1,
router_pref:2,
home_agent:1,
other:1,
@@ -53,7 +55,9 @@ struct icmp6hdr {
other:1,
home_agent:1,
router_pref:2,
- reserved:3;
+ proxy:1,
+ slaac_var_plen:1,
+ reserved:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -78,9 +82,9 @@ struct icmp6hdr {
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
+#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
};
-
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-v2-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-v2-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 13:09:55.762384640 +0100
@@ -11,6 +11,8 @@
/*
* Changes:
*
+ * Dmytro Shytyi : Variable SLAAC: SLAAC with
+ * <dmytro@shytyi.net> prefixes of arbitrary length.
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
* Andi Kleen : kill double kfree on module
@@ -142,7 +144,12 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode);
+unsigned char reverse_bits(unsigned char num);
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1314,9 +1321,21 @@ static int ipv6_create_tempaddr(struct i
struct inet6_ifaddr *ift;
struct ifa6_config cfg;
long max_desync_factor;
- struct in6_addr addr;
+
+ struct in6_addr temp, addr;
+
int ret = 0;
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
write_lock_bh(&idev->lock);
retry:
@@ -1340,9 +1359,30 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+
+ memcpy(&host_id, temp.s6_addr32, sizeof(host_id));
+ memcpy(&net_prfx, addr.s6_addr, sizeof(net_prfx));
+
+ mask_host_id = ifp->prefix_len != 128 ? (mask_128 << ifp->prefix_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(addr.s6_addr, &ipv6addr, 16);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2576,9 +2616,61 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
int create = 0;
+ if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ struct inet6_ifaddr *result = NULL;
+ struct inet6_ifaddr *result_base = NULL;
+ __int128 mask_128;
+ __int128 mask_net_prfx;
+ __int128 net_prfx;
+ __int128 curr_net_prfx;
+ int hostid_len;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ /* 128bit network prefix mask calculation */
+ hostid_len = 128 - pinfo->prefix_len;
+ mask_net_prfx = pinfo->prefix_len != 128 ? (mask_128 << pinfo->prefix_len) : 0x0;
+ mask_net_prfx = ~mask_net_prfx;
+ memcpy(mask_host_id_arr, &mask_net_prfx, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_net_prfx, mask_host_id_arr, 16);
+
+ /* Received/new IPv6 prefix */
+ memcpy(&net_prfx, pinfo->prefix.s6_addr32, 16);
+ net_prfx &= mask_net_prfx;
+
+ /* Configured/old IPv6 prefix */
+ memcpy(&curr_net_prfx, ifp->addr.s6_addr32, 16);
+ curr_net_prfx &= mask_net_prfx;
+
+ /* IPv6 prefixes comparison */
+ if ((net_prfx ^ curr_net_prfx) == 0 &&
+ pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+ } else {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2781,9 +2873,35 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ goto put;
+ } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ * Contact: Dmytro Shytyi.
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3264,6 +3382,119 @@ retry:
return 0;
}
+unsigned char reverse_bits(unsigned char num)
+{
+ unsigned char count = sizeof(num) * 8 - 1;
+ unsigned char reverse_num = num;
+
+ num >>= 1;
+ while (num) {
+ reverse_num <<= 1;
+ reverse_num |= num & 1;
+ num >>= 1;
+ count--;
+ }
+ reverse_num <<= count;
+ return reverse_num;
+}
+
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static DEFINE_SPINLOCK(lock);
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+
+ struct in6_addr secret;
+ struct in6_addr temp;
+ struct net *net = dev_net(idev->dev);
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+
+ memcpy(&host_id, temp.s6_addr32, 16);
+ memcpy(&net_prfx, address->s6_addr32, 16);
+
+ mask_host_id = rcvd_prfx_len != 128 ? (mask_128 << rcvd_prfx_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(temp.s6_addr32, &ipv6addr, 16);
+
+ *address = temp;
+
+ return 0;
+}
+
static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
struct ipv6_stable_secret *s = &idev->cnf.stable_secret;
diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-v2-5.10.0-rc2/net/ipv6/ndisc.c
--- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
+++ net-next-patch-v2-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 12:43:26.869499720 +0100
@@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
in6_dev->if_flags |= IF_RA_RCVD;
}
+ in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
+ IF_RA_VAR_PLEN : 0;
/*
* Remember the managed/otherconf flags from most recently
* received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-10 17:45 ` [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO Dmytro Shytyi
@ 2020-11-11 1:34 ` kernel test robot
2020-11-11 20:37 ` [PATCH net-next V2] " Dmytro Shytyi
` (2 more replies)
0 siblings, 3 replies; 49+ messages in thread
From: kernel test robot @ 2020-11-11 1:34 UTC (permalink / raw)
To: Dmytro Shytyi, kuba, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel
Cc: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 12862 bytes --]
Hi Dmytro,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Dmytro-Shytyi/Re-PATCH-net-next-net-Variable-SLAAC-SLAAC-with-prefixes-of-arbitrary-length-in-PIO/20201111-014800
base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 8be33ecfc1ffd2da20cc29e957e4cb6eb99310cb
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/0d851d20831574b490bbb131cb68f722dc2419ca
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmytro-Shytyi/Re-PATCH-net-next-net-Variable-SLAAC-SLAAC-with-prefixes-of-arbitrary-length-in-PIO/20201111-014800
git checkout 0d851d20831574b490bbb131cb68f722dc2419ca
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All error/warnings (new ones prefixed by >>):
net/ipv6/addrconf.c: In function 'ipv6_create_tempaddr':
>> net/ipv6/addrconf.c:1329:2: error: expected expression before '__int128'
1329 | __int128 host_id;
| ^~~~~~~~
net/ipv6/addrconf.c:1330:2: error: expected expression before '__int128'
1330 | __int128 net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:1331:2: error: expected expression before '__int128'
1331 | __int128 ipv6addr;
| ^~~~~~~~
net/ipv6/addrconf.c:1332:2: error: expected expression before '__int128'
1332 | __int128 mask_128;
| ^~~~~~~~
net/ipv6/addrconf.c:1333:2: error: expected expression before '__int128'
1333 | __int128 mask_host_id;
| ^~~~~~~~
net/ipv6/addrconf.c:1334:2: error: expected expression before '__int128'
1334 | __int128 mask_net_prfx;
| ^~~~~~~~
>> net/ipv6/addrconf.c:1335:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
1335 | int i;
| ^~~
>> net/ipv6/addrconf.c:1338:10: error: 'mask_128' undeclared (first use in this function)
1338 | memset(&mask_128, 0xFF, 16);
| ^~~~~~~~
net/ipv6/addrconf.c:1338:10: note: each undeclared identifier is reported only once for each function it appears in
>> net/ipv6/addrconf.c:1370:11: error: 'host_id' undeclared (first use in this function)
1370 | memcpy(&host_id, temp.s6_addr32, sizeof(host_id));
| ^~~~~~~
>> net/ipv6/addrconf.c:1371:11: error: 'net_prfx' undeclared (first use in this function)
1371 | memcpy(&net_prfx, addr.s6_addr, sizeof(net_prfx));
| ^~~~~~~~
>> net/ipv6/addrconf.c:1373:3: error: 'mask_host_id' undeclared (first use in this function); did you mean 'mask_host_id_arr'?
1373 | mask_host_id = ifp->prefix_len != 128 ? (mask_128 << ifp->prefix_len) : 0x0;
| ^~~~~~~~~~~~
| mask_host_id_arr
>> net/ipv6/addrconf.c:1380:3: error: 'mask_net_prfx' undeclared (first use in this function)
1380 | mask_net_prfx = mask_128 ^ mask_host_id;
| ^~~~~~~~~~~~~
>> net/ipv6/addrconf.c:1383:3: error: 'ipv6addr' undeclared (first use in this function); did you mean 'ipv6_hdr'?
1383 | ipv6addr = net_prfx | host_id;
| ^~~~~~~~
| ipv6_hdr
net/ipv6/addrconf.c: In function 'addrconf_prefix_rcv_add_addr':
net/ipv6/addrconf.c:2626:3: error: expected expression before '__int128'
2626 | __int128 mask_128;
| ^~~~~~~~
net/ipv6/addrconf.c:2627:3: error: expected expression before '__int128'
2627 | __int128 mask_net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:2628:3: error: expected expression before '__int128'
2628 | __int128 net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:2629:3: error: expected expression before '__int128'
2629 | __int128 curr_net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:2630:3: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
2630 | int hostid_len;
| ^~~
net/ipv6/addrconf.c:2634:11: error: 'mask_128' undeclared (first use in this function)
2634 | memset(&mask_128, 0xFF, 16);
| ^~~~~~~~
net/ipv6/addrconf.c:2642:4: error: 'mask_net_prfx' undeclared (first use in this function)
2642 | mask_net_prfx = pinfo->prefix_len != 128 ? (mask_128 << pinfo->prefix_len) : 0x0;
| ^~~~~~~~~~~~~
net/ipv6/addrconf.c:2650:12: error: 'net_prfx' undeclared (first use in this function)
2650 | memcpy(&net_prfx, pinfo->prefix.s6_addr32, 16);
| ^~~~~~~~
>> net/ipv6/addrconf.c:2654:12: error: 'curr_net_prfx' undeclared (first use in this function)
2654 | memcpy(&curr_net_prfx, ifp->addr.s6_addr32, 16);
| ^~~~~~~~~~~~~
>> net/ipv6/addrconf.c:2630:7: warning: variable 'hostid_len' set but not used [-Wunused-but-set-variable]
2630 | int hostid_len;
| ^~~~~~~~~~
net/ipv6/addrconf.c: In function 'ipv6_generate_address_variable_plen':
net/ipv6/addrconf.c:3424:2: error: expected expression before '__int128'
3424 | __int128 host_id;
| ^~~~~~~~
net/ipv6/addrconf.c:3425:2: error: expected expression before '__int128'
3425 | __int128 net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:3426:2: error: expected expression before '__int128'
3426 | __int128 ipv6addr;
| ^~~~~~~~
net/ipv6/addrconf.c:3427:2: error: expected expression before '__int128'
3427 | __int128 mask_128;
| ^~~~~~~~
net/ipv6/addrconf.c:3428:2: error: expected expression before '__int128'
3428 | __int128 mask_host_id;
| ^~~~~~~~
net/ipv6/addrconf.c:3429:2: error: expected expression before '__int128'
3429 | __int128 mask_net_prfx;
| ^~~~~~~~
net/ipv6/addrconf.c:3430:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
3430 | int i;
| ^~~
net/ipv6/addrconf.c:3433:10: error: 'mask_128' undeclared (first use in this function)
3433 | memset(&mask_128, 0xFF, 16);
| ^~~~~~~~
net/ipv6/addrconf.c:3477:10: error: 'host_id' undeclared (first use in this function)
3477 | memcpy(&host_id, temp.s6_addr32, 16);
| ^~~~~~~
net/ipv6/addrconf.c:3478:10: error: 'net_prfx' undeclared (first use in this function)
3478 | memcpy(&net_prfx, address->s6_addr32, 16);
| ^~~~~~~~
net/ipv6/addrconf.c:3480:2: error: 'mask_host_id' undeclared (first use in this function); did you mean 'mask_host_id_arr'?
3480 | mask_host_id = rcvd_prfx_len != 128 ? (mask_128 << rcvd_prfx_len) : 0x0;
| ^~~~~~~~~~~~
| mask_host_id_arr
net/ipv6/addrconf.c:3487:2: error: 'mask_net_prfx' undeclared (first use in this function)
3487 | mask_net_prfx = mask_128 ^ mask_host_id;
| ^~~~~~~~~~~~~
net/ipv6/addrconf.c:3490:2: error: 'ipv6addr' undeclared (first use in this function); did you mean 'ipv6_hdr'?
3490 | ipv6addr = net_prfx | host_id;
| ^~~~~~~~
| ipv6_hdr
vim +/__int128 +1329 net/ipv6/addrconf.c
1313
1314 static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
1315 {
1316 struct inet6_dev *idev = ifp->idev;
1317 unsigned long tmp_tstamp, age;
1318 unsigned long regen_advance;
1319 unsigned long now = jiffies;
1320 s32 cnf_temp_preferred_lft;
1321 struct inet6_ifaddr *ift;
1322 struct ifa6_config cfg;
1323 long max_desync_factor;
1324
1325 struct in6_addr temp, addr;
1326
1327 int ret = 0;
1328
> 1329 __int128 host_id;
1330 __int128 net_prfx;
1331 __int128 ipv6addr;
1332 __int128 mask_128;
1333 __int128 mask_host_id;
1334 __int128 mask_net_prfx;
> 1335 int i;
1336 unsigned char mask_host_id_arr[128];
1337
> 1338 memset(&mask_128, 0xFF, 16);
1339 write_lock_bh(&idev->lock);
1340
1341 retry:
1342 in6_dev_hold(idev);
1343 if (idev->cnf.use_tempaddr <= 0) {
1344 write_unlock_bh(&idev->lock);
1345 pr_info("%s: use_tempaddr is disabled\n", __func__);
1346 in6_dev_put(idev);
1347 ret = -1;
1348 goto out;
1349 }
1350 spin_lock_bh(&ifp->lock);
1351 if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
1352 idev->cnf.use_tempaddr = -1; /*XXX*/
1353 spin_unlock_bh(&ifp->lock);
1354 write_unlock_bh(&idev->lock);
1355 pr_warn("%s: regeneration time exceeded - disabled temporary address support\n",
1356 __func__);
1357 in6_dev_put(idev);
1358 ret = -1;
1359 goto out;
1360 }
1361 in6_ifa_hold(ifp);
1362
1363 if (ifp->prefix_len == 64) {
1364 memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
1365 ipv6_gen_rnd_iid(&addr);
1366 } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
1367 memcpy(addr.s6_addr, ifp->addr.s6_addr, 16);
1368 get_random_bytes(temp.s6_addr32, 16);
1369
> 1370 memcpy(&host_id, temp.s6_addr32, sizeof(host_id));
> 1371 memcpy(&net_prfx, addr.s6_addr, sizeof(net_prfx));
1372
> 1373 mask_host_id = ifp->prefix_len != 128 ? (mask_128 << ifp->prefix_len) : 0x0;
1374 memcpy(mask_host_id_arr, &mask_host_id, 16);
1375 for (i = 0; i < 128; i++)
1376 mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
1377 memcpy(&mask_host_id, mask_host_id_arr, 16);
1378 host_id = host_id & mask_host_id;
1379
> 1380 mask_net_prfx = mask_128 ^ mask_host_id;
1381 net_prfx = net_prfx & mask_net_prfx;
1382
> 1383 ipv6addr = net_prfx | host_id;
1384 memcpy(addr.s6_addr, &ipv6addr, 16);
1385 }
1386 age = (now - ifp->tstamp) / HZ;
1387
1388 regen_advance = idev->cnf.regen_max_retry *
1389 idev->cnf.dad_transmits *
1390 max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
1391
1392 /* recalculate max_desync_factor each time and update
1393 * idev->desync_factor if it's larger
1394 */
1395 cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft);
1396 max_desync_factor = min_t(__u32,
1397 idev->cnf.max_desync_factor,
1398 cnf_temp_preferred_lft - regen_advance);
1399
1400 if (unlikely(idev->desync_factor > max_desync_factor)) {
1401 if (max_desync_factor > 0) {
1402 get_random_bytes(&idev->desync_factor,
1403 sizeof(idev->desync_factor));
1404 idev->desync_factor %= max_desync_factor;
1405 } else {
1406 idev->desync_factor = 0;
1407 }
1408 }
1409
1410 memset(&cfg, 0, sizeof(cfg));
1411 cfg.valid_lft = min_t(__u32, ifp->valid_lft,
1412 idev->cnf.temp_valid_lft + age);
1413 cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor;
1414 cfg.preferred_lft = min_t(__u32, ifp->prefered_lft, cfg.preferred_lft);
1415
1416 cfg.plen = ifp->prefix_len;
1417 tmp_tstamp = ifp->tstamp;
1418 spin_unlock_bh(&ifp->lock);
1419
1420 write_unlock_bh(&idev->lock);
1421
1422 /* A temporary address is created only if this calculated Preferred
1423 * Lifetime is greater than REGEN_ADVANCE time units. In particular,
1424 * an implementation must not create a temporary address with a zero
1425 * Preferred Lifetime.
1426 * Use age calculation as in addrconf_verify to avoid unnecessary
1427 * temporary addresses being generated.
1428 */
1429 age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
1430 if (cfg.preferred_lft <= regen_advance + age) {
1431 in6_ifa_put(ifp);
1432 in6_dev_put(idev);
1433 ret = -1;
1434 goto out;
1435 }
1436
1437 cfg.ifa_flags = IFA_F_TEMPORARY;
1438 /* set in addrconf_prefix_rcv() */
1439 if (ifp->flags & IFA_F_OPTIMISTIC)
1440 cfg.ifa_flags |= IFA_F_OPTIMISTIC;
1441
1442 cfg.pfx = &addr;
1443 cfg.scope = ipv6_addr_scope(cfg.pfx);
1444
1445 ift = ipv6_add_addr(idev, &cfg, block, NULL);
1446 if (IS_ERR(ift)) {
1447 in6_ifa_put(ifp);
1448 in6_dev_put(idev);
1449 pr_info("%s: retry temporary address regeneration\n", __func__);
1450 write_lock_bh(&idev->lock);
1451 goto retry;
1452 }
1453
1454 spin_lock_bh(&ift->lock);
1455 ift->ifpub = ifp;
1456 ift->cstamp = now;
1457 ift->tstamp = tmp_tstamp;
1458 spin_unlock_bh(&ift->lock);
1459
1460 addrconf_dad_start(ift);
1461 in6_ifa_put(ift);
1462 in6_dev_put(idev);
1463 out:
1464 return ret;
1465 }
1466
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 53504 bytes --]
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V2] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-11 1:34 ` kernel test robot
@ 2020-11-11 20:37 ` Dmytro Shytyi
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
2020-11-13 0:24 ` [PATCH net-next] " Jakub Kicinski
2 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-11 20:37 UTC (permalink / raw)
To: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
Reported-by: kernel test robot <lkp@intel.com>
---
diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
--- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
+++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
@@ -22,6 +22,12 @@
#define IF_RS_SENT 0x10
#define IF_READY 0x80000000
+/* Variable SLAAC (Contact: Dmytro Shytyi)
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+#define IF_RA_VAR_PLEN 0x08
+
/* prefix flags */
#define IF_PREFIX_ONLINK 0x01
#define IF_PREFIX_AUTOCONF 0x02
diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
--- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
+++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
@@ -42,7 +42,9 @@ struct icmp6hdr {
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:3,
+ __u8 reserved:1,
+ slaac_var_plen:1,
+ proxy:1,
router_pref:2,
home_agent:1,
other:1,
@@ -53,7 +55,9 @@ struct icmp6hdr {
other:1,
home_agent:1,
router_pref:2,
- reserved:3;
+ proxy:1,
+ slaac_var_plen:1,
+ reserved:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -78,9 +82,9 @@ struct icmp6hdr {
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
+#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
};
-
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-11 19:47:08.529992394 +0100
@@ -11,6 +11,8 @@
/*
* Changes:
*
+ * Dmytro Shytyi : Variable SLAAC: SLAAC with
+ * <dmytro@shytyi.net> prefixes of arbitrary length.
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
* Andi Kleen : kill double kfree on module
@@ -142,7 +144,12 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode);
+unsigned char reverse_bits(unsigned char num);
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1314,11 +1321,26 @@ static int ipv6_create_tempaddr(struct i
struct inet6_ifaddr *ift;
struct ifa6_config cfg;
long max_desync_factor;
+
struct in6_addr addr;
- int ret = 0;
- write_lock_bh(&idev->lock);
+ int ret;
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ struct in6_addr temp;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ write_lock_bh(&idev->lock);
+#endif
+ ret = 0;
retry:
in6_dev_hold(idev);
if (idev->cnf.use_tempaddr <= 0) {
@@ -1340,9 +1362,32 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+
+ memcpy(&host_id, temp.s6_addr32, sizeof(host_id));
+ memcpy(&net_prfx, addr.s6_addr, sizeof(net_prfx));
+
+ mask_host_id = ifp->prefix_len != 128 ? (mask_128 << ifp->prefix_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(addr.s6_addr, &ipv6addr, 16);
+#endif
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -1398,7 +1443,11 @@ retry:
/* set in addrconf_prefix_rcv() */
if (ifp->flags & IFA_F_OPTIMISTIC)
cfg.ifa_flags |= IFA_F_OPTIMISTIC;
-
+
+ if (in6_pton("::", -1, addr.s6_addr, -1, NULL)) {
+ ret = -1;
+ goto out;
+ }
cfg.pfx = &addr;
cfg.scope = ipv6_addr_scope(cfg.pfx);
@@ -2576,9 +2625,64 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
int create = 0;
+ if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ struct inet6_ifaddr *result = NULL;
+ struct inet6_ifaddr *result_base = NULL;
+ __int128 mask_128;
+ __int128 mask_net_prfx;
+ __int128 net_prfx;
+ __int128 curr_net_prfx;
+ int hostid_len;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ /* 128bit network prefix mask calculation */
+ hostid_len = 128 - pinfo->prefix_len;
+ mask_net_prfx =
+ pinfo->prefix_len != 128 ? (mask_128 << pinfo->prefix_len) : 0x0;
+ mask_net_prfx = ~mask_net_prfx;
+ memcpy(mask_host_id_arr, &mask_net_prfx, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_net_prfx, mask_host_id_arr, 16);
+
+ /* Received/new IPv6 prefix */
+ memcpy(&net_prfx, pinfo->prefix.s6_addr32, 16);
+ net_prfx &= mask_net_prfx;
+
+ /* Configured/old IPv6 prefix */
+ memcpy(&curr_net_prfx, ifp->addr.s6_addr32, 16);
+ curr_net_prfx &= mask_net_prfx;
+
+ /* IPv6 prefixes comparison */
+ if ((net_prfx ^ curr_net_prfx) == 0 &&
+ pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+#endif
+ } else {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2781,9 +2885,35 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ goto put;
+ } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ * Contact: Dmytro Shytyi.
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3264,6 +3394,120 @@ retry:
return 0;
}
+unsigned char reverse_bits(unsigned char num)
+{
+ unsigned char count = sizeof(num) * 8 - 1;
+ unsigned char reverse_num = num;
+
+ num >>= 1;
+ while (num) {
+ reverse_num <<= 1;
+ reverse_num |= num & 1;
+ num >>= 1;
+ count--;
+ }
+ reverse_num <<= count;
+ return reverse_num;
+}
+
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ static DEFINE_SPINLOCK(lock);
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+
+ struct in6_addr secret;
+ struct in6_addr temp;
+ struct net *net = dev_net(idev->dev);
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+
+ memcpy(&host_id, temp.s6_addr32, 16);
+ memcpy(&net_prfx, address->s6_addr32, 16);
+
+ mask_host_id = rcvd_prfx_len != 128 ? (mask_128 << rcvd_prfx_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(temp.s6_addr32, &ipv6addr, 16);
+
+ *address = temp;
+#endif
+ return 0;
+}
+
static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
struct ipv6_stable_secret *s = &idev->cnf.stable_secret;
diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
--- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
@@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
in6_dev->if_flags |= IF_RA_RCVD;
}
+ in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
+ IF_RA_VAR_PLEN : 0;
/*
* Remember the managed/otherconf flags from most recently
* received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V3] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-11 1:34 ` kernel test robot
2020-11-11 20:37 ` [PATCH net-next V2] " Dmytro Shytyi
@ 2020-11-12 15:44 ` Dmytro Shytyi
2020-11-12 16:55 ` Hideaki Yoshifuji
` (2 more replies)
2020-11-13 0:24 ` [PATCH net-next] " Jakub Kicinski
2 siblings, 3 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-12 15:44 UTC (permalink / raw)
To: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
Reported-by: kernel test robot <lkp@intel.com>
---
diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
--- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
+++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
@@ -22,6 +22,12 @@
#define IF_RS_SENT 0x10
#define IF_READY 0x80000000
+/* Variable SLAAC (Contact: Dmytro Shytyi)
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+#define IF_RA_VAR_PLEN 0x08
+
/* prefix flags */
#define IF_PREFIX_ONLINK 0x01
#define IF_PREFIX_AUTOCONF 0x02
diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
--- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
+++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
@@ -42,7 +42,9 @@ struct icmp6hdr {
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:3,
+ __u8 reserved:1,
+ slaac_var_plen:1,
+ proxy:1,
router_pref:2,
home_agent:1,
other:1,
@@ -53,7 +55,9 @@ struct icmp6hdr {
other:1,
home_agent:1,
router_pref:2,
- reserved:3;
+ proxy:1,
+ slaac_var_plen:1,
+ reserved:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -78,9 +82,9 @@ struct icmp6hdr {
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
+#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
};
-
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-12 16:27:26.765361712 +0100
@@ -11,6 +11,8 @@
/*
* Changes:
*
+ * Dmytro Shytyi : Variable SLAAC: SLAAC with
+ * <dmytro@shytyi.net> prefixes of arbitrary length.
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
* Andi Kleen : kill double kfree on module
@@ -142,7 +144,12 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode);
+unsigned char reverse_bits(unsigned char num);
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1314,11 +1321,26 @@ static int ipv6_create_tempaddr(struct i
struct inet6_ifaddr *ift;
struct ifa6_config cfg;
long max_desync_factor;
+
struct in6_addr addr;
- int ret = 0;
- write_lock_bh(&idev->lock);
+ int ret;
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ struct in6_addr temp;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+#endif
+ write_lock_bh(&idev->lock);
+ ret = 0;
retry:
in6_dev_hold(idev);
if (idev->cnf.use_tempaddr <= 0) {
@@ -1340,9 +1362,32 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+
+ memcpy(&host_id, temp.s6_addr32, sizeof(host_id));
+ memcpy(&net_prfx, addr.s6_addr, sizeof(net_prfx));
+
+ mask_host_id = ifp->prefix_len != 128 ? (mask_128 << ifp->prefix_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(addr.s6_addr, &ipv6addr, 16);
+#endif
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -1398,7 +1443,11 @@ retry:
/* set in addrconf_prefix_rcv() */
if (ifp->flags & IFA_F_OPTIMISTIC)
cfg.ifa_flags |= IFA_F_OPTIMISTIC;
-
+
+ if (in6_pton("::", -1, addr.s6_addr, -1, NULL)) {
+ ret = -1;
+ goto out;
+ }
cfg.pfx = &addr;
cfg.scope = ipv6_addr_scope(cfg.pfx);
@@ -2576,9 +2625,64 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
int create = 0;
+ if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ struct inet6_ifaddr *result = NULL;
+ struct inet6_ifaddr *result_base = NULL;
+ __int128 mask_128;
+ __int128 mask_net_prfx;
+ __int128 net_prfx;
+ __int128 curr_net_prfx;
+ int hostid_len;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ /* 128bit network prefix mask calculation */
+ hostid_len = 128 - pinfo->prefix_len;
+ mask_net_prfx =
+ pinfo->prefix_len != 128 ? (mask_128 << pinfo->prefix_len) : 0x0;
+ mask_net_prfx = ~mask_net_prfx;
+ memcpy(mask_host_id_arr, &mask_net_prfx, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_net_prfx, mask_host_id_arr, 16);
+
+ /* Received/new IPv6 prefix */
+ memcpy(&net_prfx, pinfo->prefix.s6_addr32, 16);
+ net_prfx &= mask_net_prfx;
+
+ /* Configured/old IPv6 prefix */
+ memcpy(&curr_net_prfx, ifp->addr.s6_addr32, 16);
+ curr_net_prfx &= mask_net_prfx;
+
+ /* IPv6 prefixes comparison */
+ if ((net_prfx ^ curr_net_prfx) == 0 &&
+ pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+#endif
+ } else {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2781,9 +2885,35 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ goto put;
+ } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ * Contact: Dmytro Shytyi.
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3264,6 +3394,120 @@ retry:
return 0;
}
+unsigned char reverse_bits(unsigned char num)
+{
+ unsigned char count = sizeof(num) * 8 - 1;
+ unsigned char reverse_num = num;
+
+ num >>= 1;
+ while (num) {
+ reverse_num <<= 1;
+ reverse_num |= num & 1;
+ num >>= 1;
+ count--;
+ }
+ reverse_num <<= count;
+ return reverse_num;
+}
+
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+ static DEFINE_SPINLOCK(lock);
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+
+ struct in6_addr secret;
+ struct in6_addr temp;
+ struct net *net = dev_net(idev->dev);
+ __int128 host_id;
+ __int128 net_prfx;
+ __int128 ipv6addr;
+ __int128 mask_128;
+ __int128 mask_host_id;
+ __int128 mask_net_prfx;
+ int i;
+ unsigned char mask_host_id_arr[128];
+
+ memset(&mask_128, 0xFF, 16);
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+
+ memcpy(&host_id, temp.s6_addr32, 16);
+ memcpy(&net_prfx, address->s6_addr32, 16);
+
+ mask_host_id = rcvd_prfx_len != 128 ? (mask_128 << rcvd_prfx_len) : 0x0;
+ memcpy(mask_host_id_arr, &mask_host_id, 16);
+ for (i = 0; i < 128; i++)
+ mask_host_id_arr[i] = reverse_bits(mask_host_id_arr[i]);
+ memcpy(&mask_host_id, mask_host_id_arr, 16);
+ host_id = host_id & mask_host_id;
+
+ mask_net_prfx = mask_128 ^ mask_host_id;
+ net_prfx = net_prfx & mask_net_prfx;
+
+ ipv6addr = net_prfx | host_id;
+ memcpy(temp.s6_addr32, &ipv6addr, 16);
+
+ *address = temp;
+#endif
+ return 0;
+}
+
static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
struct ipv6_stable_secret *s = &idev->cnf.stable_secret;
diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
--- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
@@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
in6_dev->if_flags |= IF_RA_RCVD;
}
+ in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
+ IF_RA_VAR_PLEN : 0;
/*
* Remember the managed/otherconf flags from most recently
* received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V3] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
@ 2020-11-12 16:55 ` Hideaki Yoshifuji
2020-11-13 1:50 ` Dmytro Shytyi
2020-11-13 0:21 ` Jakub Kicinski
2020-11-13 1:56 ` [PATCH net-next V4] " Dmytro Shytyi
2 siblings, 1 reply; 49+ messages in thread
From: Hideaki Yoshifuji @ 2020-11-12 16:55 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel,
Hideaki Yoshifuji
Hi,
2020年11月13日(金) 0:46 Dmytro Shytyi <dmytro@shytyi.net>:
>
> Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> Load-Balancer and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> Reported-by: kernel test robot <lkp@intel.com>
> ---
> - write_lock_bh(&idev->lock);
> + int ret;
> +#if defined(CONFIG_ARCH_SUPPORTS_INT128)
> + __int128 host_id;
> + __int128 net_prfx;
:
No, this does not help anything.
Please do not rely on __int128.
--yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V3] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
2020-11-12 16:55 ` Hideaki Yoshifuji
@ 2020-11-13 0:21 ` Jakub Kicinski
2020-11-13 1:50 ` Dmytro Shytyi
2020-11-13 1:56 ` [PATCH net-next V4] " Dmytro Shytyi
2 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-13 0:21 UTC (permalink / raw)
To: Dmytro Shytyi; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
On Thu, 12 Nov 2020 16:44:54 +0100 Dmytro Shytyi wrote:
> Reported-by: kernel test robot <lkp@intel.com>
You don't have to add the reported by tag just because the bot pointed
out issues in the previous version.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-11 1:34 ` kernel test robot
2020-11-11 20:37 ` [PATCH net-next V2] " Dmytro Shytyi
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
@ 2020-11-13 0:24 ` Jakub Kicinski
2020-11-13 0:32 ` [kbuild-all] " Li, Philip
2020-11-13 1:43 ` Dave Hansen
2 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-13 0:24 UTC (permalink / raw)
To: kernel test robot
Cc: Dmytro Shytyi, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel, kbuild-all
On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
Good people of kernel test robot, could you please rephrase this to say
that the tag is only appropriate if someone is sending a fix up/follow
up patch?
Folks keep adding those tags on the next revisions of the their patches
which is quite misleading.
^ permalink raw reply [flat|nested] 49+ messages in thread
* RE: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 0:24 ` [PATCH net-next] " Jakub Kicinski
@ 2020-11-13 0:32 ` Li, Philip
2020-11-13 0:51 ` Jakub Kicinski
2020-11-13 1:43 ` Dave Hansen
1 sibling, 1 reply; 49+ messages in thread
From: Li, Philip @ 2020-11-13 0:32 UTC (permalink / raw)
To: Jakub Kicinski, lkp
Cc: Dmytro Shytyi, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel, kbuild-all
> Subject: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC with
> prefixes of arbitrary length in PIO
>
> On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
> > If you fix the issue, kindly add following tag as appropriate
> > Reported-by: kernel test robot <lkp@intel.com>
>
> Good people of kernel test robot, could you please rephrase this to say
> that the tag is only appropriate if someone is sending a fix up/follow
> up patch?
Thanks for the input, based on your suggestion how about
Kindly add below tag as appropriate if you send a fix up/follow up patch
Reported-by: kernel test robot <lkp@intel.com>
Or any wording change suggestion to make it more clear/friendly?
Thanks
>
> Folks keep adding those tags on the next revisions of the their patches
> which is quite misleading.
> _______________________________________________
> kbuild-all mailing list -- kbuild-all@lists.01.org
> To unsubscribe send an email to kbuild-all-leave@lists.01.org
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 0:32 ` [kbuild-all] " Li, Philip
@ 2020-11-13 0:51 ` Jakub Kicinski
2020-11-13 1:01 ` Li, Philip
0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-13 0:51 UTC (permalink / raw)
To: Li, Philip
Cc: lkp, Dmytro Shytyi, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel, kbuild-all
On Fri, 13 Nov 2020 00:32:55 +0000 Li, Philip wrote:
> > Subject: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC with
> > prefixes of arbitrary length in PIO
> >
> > On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
> > > If you fix the issue, kindly add following tag as appropriate
> > > Reported-by: kernel test robot <lkp@intel.com>
> >
> > Good people of kernel test robot, could you please rephrase this to say
> > that the tag is only appropriate if someone is sending a fix up/follow
> > up patch?
> Thanks for the input, based on your suggestion how about
>
> Kindly add below tag as appropriate if you send a fix up/follow up patch
I'm not sure myself how best to phrase it, I'm not a native speaker.
How about:
Kindly add below tag if you send a new patch solely addressing this issue
> Reported-by: kernel test robot <lkp@intel.com>
>
> Or any wording change suggestion to make it more clear/friendly?
^ permalink raw reply [flat|nested] 49+ messages in thread
* RE: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 0:51 ` Jakub Kicinski
@ 2020-11-13 1:01 ` Li, Philip
0 siblings, 0 replies; 49+ messages in thread
From: Li, Philip @ 2020-11-13 1:01 UTC (permalink / raw)
To: Jakub Kicinski
Cc: lkp, Dmytro Shytyi, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel, kbuild-all
>
> On Fri, 13 Nov 2020 00:32:55 +0000 Li, Philip wrote:
> > > Subject: [kbuild-all] Re: [PATCH net-next] net: Variable SLAAC: SLAAC
> with
> > > prefixes of arbitrary length in PIO
> > >
> > > On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
> > > > If you fix the issue, kindly add following tag as appropriate
> > > > Reported-by: kernel test robot <lkp@intel.com>
> > >
> > > Good people of kernel test robot, could you please rephrase this to say
> > > that the tag is only appropriate if someone is sending a fix up/follow
> > > up patch?
> > Thanks for the input, based on your suggestion how about
> >
> > Kindly add below tag as appropriate if you send a fix up/follow up patch
>
> I'm not sure myself how best to phrase it, I'm not a native speaker.
> How about:
>
> Kindly add below tag if you send a new patch solely addressing this issue
Thanks, we will consider this, and provide update next week to gather
more inputs. If anyone has further suggestion, it will be very welcome.
There did have some confusion and discussed earlier actually regarding
when/how to add the Reported-by, thus we use appropriate to let developer
decide the best choice for his own situation. But if it leads to confusion,
we will keep looking for a better way.
BTW: if we just remove this message line, and leave below Reported-by only, would
it be a good choice?
>
> > Reported-by: kernel test robot <lkp@intel.com>
> >
> > Or any wording change suggestion to make it more clear/friendly?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 0:24 ` [PATCH net-next] " Jakub Kicinski
2020-11-13 0:32 ` [kbuild-all] " Li, Philip
@ 2020-11-13 1:43 ` Dave Hansen
2020-11-13 1:53 ` Jakub Kicinski
1 sibling, 1 reply; 49+ messages in thread
From: Dave Hansen @ 2020-11-13 1:43 UTC (permalink / raw)
To: Jakub Kicinski, kernel test robot
Cc: Dmytro Shytyi, kuznet, yoshfuji, liuhangbin, davem, netdev,
linux-kernel, kbuild-all
On 11/12/20 4:24 PM, Jakub Kicinski wrote:
> On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
>> If you fix the issue, kindly add following tag as appropriate
>> Reported-by: kernel test robot <lkp@intel.com>
> Good people of kernel test robot, could you please rephrase this to say
> that the tag is only appropriate if someone is sending a fix up/follow
> up patch?
>
> Folks keep adding those tags on the next revisions of the their patches
> which is quite misleading.
I think it's still fair for the lkp folks to get *some* credit for
reporting these bugs. I mean, the stated reason[1] for it existing is:
The Reported-by tag gives credit to people who find bugs and
report them and it hopefully inspires them to help us again in
the future.
I do agree, though, that it's confusing *what* they reported, especially
if the patch in question is fixing something *else*. Rather than invent
a new tag, maybe a comment would suffice:
Reported-by: kernel test robot <lkp@intel.com> # bug in earlier revision
1.
https://www.kernel.org/doc/html/v4.17/process/submitting-patches.html#using-reported-by-tested-by-reviewed-by-suggested-by-and-fixes
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V3] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-12 16:55 ` Hideaki Yoshifuji
@ 2020-11-13 1:50 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-13 1:50 UTC (permalink / raw)
To: Hideaki Yoshifuji
Cc: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Hello,
---- On Thu, 12 Nov 2020 17:55:08 +0100 Hideaki Yoshifuji <hideaki.yoshifuji@miraclelinux.com> wrote ----
> Hi,
>
> 2020年11月13日(金) 0:46 Dmytro Shytyi <dmytro@shytyi.net>:
> >
> > Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > Load-Balancer and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > Reported-by: kernel test robot <lkp@intel.com>
> > ---
>
> > - write_lock_bh(&idev->lock);
> > + int ret;
> > +#if defined(CONFIG_ARCH_SUPPORTS_INT128)
> > + __int128 host_id;
> > + __int128 net_prfx;
> :
>
> No, this does not help anything.
> Please do not rely on __int128.
[Dmytro] Understood. Thank you.
> --yoshfuji
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V3] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 0:21 ` Jakub Kicinski
@ 2020-11-13 1:50 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-13 1:50 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Hello,
---- On Fri, 13 Nov 2020 01:21:56 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> On Thu, 12 Nov 2020 16:44:54 +0100 Dmytro Shytyi wrote:
> > Reported-by: kernel test robot <lkp@intel.com>
>
> You don't have to add the reported by tag just because the bot pointed
> out issues in the previous version.
>
[Dmytro] Understood. Thank you for the comment.
Dmytro SHYTYI
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 1:43 ` Dave Hansen
@ 2020-11-13 1:53 ` Jakub Kicinski
2020-11-13 2:01 ` Dave Hansen
0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-13 1:53 UTC (permalink / raw)
To: Dave Hansen
Cc: kernel test robot, Dmytro Shytyi, kuznet, yoshfuji, liuhangbin,
davem, netdev, linux-kernel, kbuild-all
On Thu, 12 Nov 2020 17:43:56 -0800 Dave Hansen wrote:
> On 11/12/20 4:24 PM, Jakub Kicinski wrote:
> > On Wed, 11 Nov 2020 09:34:24 +0800 kernel test robot wrote:
> >> If you fix the issue, kindly add following tag as appropriate
> >> Reported-by: kernel test robot <lkp@intel.com>
> > Good people of kernel test robot, could you please rephrase this to say
> > that the tag is only appropriate if someone is sending a fix up/follow
> > up patch?
> >
> > Folks keep adding those tags on the next revisions of the their patches
> > which is quite misleading.
>
> I think it's still fair for the lkp folks to get *some* credit for
> reporting these bugs. I mean, the stated reason[1] for it existing is:
>
> The Reported-by tag gives credit to people who find bugs and
> report them and it hopefully inspires them to help us again in
> the future.
>
> I do agree, though, that it's confusing *what* they reported, especially
> if the patch in question is fixing something *else*. Rather than invent
> a new tag, maybe a comment would suffice:
>
> Reported-by: kernel test robot <lkp@intel.com> # bug in earlier revision
Fine by me, although its not common to add Reported-by tags for people
who point out issues in review, so why add a tag for the bot?
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V4] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
2020-11-12 16:55 ` Hideaki Yoshifuji
2020-11-13 0:21 ` Jakub Kicinski
@ 2020-11-13 1:56 ` Dmytro Shytyi
2020-11-13 12:38 ` Hideaki Yoshifuji
2020-11-13 19:36 ` [PATCH net-next V5] " Dmytro Shytyi
2 siblings, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-13 1:56 UTC (permalink / raw)
To: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
--- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
+++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
@@ -22,6 +22,12 @@
#define IF_RS_SENT 0x10
#define IF_READY 0x80000000
+/* Variable SLAAC (Contact: Dmytro Shytyi)
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+#define IF_RA_VAR_PLEN 0x08
+
/* prefix flags */
#define IF_PREFIX_ONLINK 0x01
#define IF_PREFIX_AUTOCONF 0x02
diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
--- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
+++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
@@ -42,7 +42,9 @@ struct icmp6hdr {
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:3,
+ __u8 reserved:1,
+ slaac_var_plen:1,
+ proxy:1,
router_pref:2,
home_agent:1,
other:1,
@@ -53,7 +55,9 @@ struct icmp6hdr {
other:1,
home_agent:1,
router_pref:2,
- reserved:3;
+ proxy:1,
+ slaac_var_plen:1,
+ reserved:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -78,9 +82,9 @@ struct icmp6hdr {
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
+#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
};
-
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 02:30:25.552724864 +0100
@@ -11,6 +11,8 @@
/*
* Changes:
*
+ * Dmytro Shytyi : Variable SLAAC: SLAAC with
+ * <dmytro@shytyi.net> prefixes of arbitrary length.
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
* Andi Kleen : kill double kfree on module
@@ -142,7 +144,12 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode);
+static void ipv6_plen_to_mask(int plen, struct in6_addr *net_mask);
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1315,10 +1322,14 @@ static int ipv6_create_tempaddr(struct i
struct ifa6_config cfg;
long max_desync_factor;
struct in6_addr addr;
- int ret = 0;
+ int ret;
+ struct in6_addr net_mask;
+ struct in6_addr temp;
+ struct in6_addr ipv6addr;
+ int i;
write_lock_bh(&idev->lock);
-
+ ret = 0;
retry:
in6_dev_hold(idev);
if (idev->cnf.use_tempaddr <= 0) {
@@ -1340,9 +1351,26 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+ memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+
+ /* tranfrom prefix len into mask */
+ ipv6_plen_to_mask(ifp->prefix_len, &net_mask);
+
+ for (i = 0; i < 4; i++) {
+ /* network prefix */
+ ipv6addr.s6_addr32[i] = addr.s6_addr32[i] & net_mask.s6_addr32[i];
+ /* host id */
+ ipv6addr.s6_addr32[i] |= temp.s6_addr32[i] & ~net_mask.s6_addr32[i];
+ }
+
+ memcpy(addr.s6_addr, ipv6addr.s6_addr32, 16);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2576,9 +2604,57 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
int create = 0;
+ if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ struct inet6_ifaddr *result = NULL;
+ struct inet6_ifaddr *result_base = NULL;
+ struct in6_addr net_mask;
+ struct in6_addr net_prfx;
+ struct in6_addr curr_net_prfx;
+ bool prfxs_equal;
+ int i;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+
+ /* tranfrom prefix len into mask */
+ ipv6_plen_to_mask(pinfo->prefix_len, &net_mask);
+ /* Prepare network prefixes */
+ for (i = 0; i < 4; i++) {
+ /* Received/new network prefix */
+ net_prfx.s6_addr32[i] =
+ pinfo->prefix.s6_addr32[i] & net_mask.s6_addr32[i];
+ /* Configured/old IPv6 prefix */
+ curr_net_prfx.s6_addr32[i] =
+ ifp->addr.s6_addr32[i] & net_mask.s6_addr32[i];
+ }
+ /* Compare network prefixes */
+ prfxs_equal = 1;
+ for (i = 0; i < 4; i++) {
+ if ((net_prfx.s6_addr32[i] ^ curr_net_prfx.s6_addr32[i]) != 0)
+ prfxs_equal = 0;
+ }
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+ } else {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2781,9 +2857,35 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ goto put;
+ } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ * Contact: Dmytro Shytyi.
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3264,6 +3366,118 @@ retry:
return 0;
}
+static void ipv6_plen_to_mask(int plen, struct in6_addr *net_mask)
+{
+ int i, plen_bytes;
+ char bit_array[7] = {0b10000000,
+ 0b11000000,
+ 0b11100000,
+ 0b11110000,
+ 0b11111000,
+ 0b11111100,
+ 0b11111110};
+
+ if (plen <= 0 || plen > 128)
+ pr_err("Unexpected plen: %d", plen);
+
+ memset(net_mask, 0x00, sizeof(*net_mask));
+
+ /* We set all bits == 1 of s6_addr[i] */
+ plen_bytes = plen / 8;
+ for (i = 0; i < plen_bytes; i++)
+ net_mask->s6_addr[i] = 0xff;
+
+ /* We add bits from the bit_array to
+ * netmask starting from plen_bytes position
+ */
+ if (plen % 8)
+ net_mask->s6_addr[plen_bytes] = bit_array[(plen % 8) - 1];
+ memcpy(net_mask->s6_addr32, net_mask->s6_addr, 16);
+}
+
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static DEFINE_SPINLOCK(lock);
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+
+ struct in6_addr ipv6_temp_addr;
+ struct in6_addr net_mask;
+ struct in6_addr secret;
+ struct in6_addr temp;
+ struct net *net = dev_net(idev->dev);
+ int i;
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+
+ /* convert plen to mask */
+ ipv6_plen_to_mask(rcvd_prfx_len, &net_mask);
+ for (i = 0; i < 4; i++) {
+ /* network prefix */
+ ipv6_temp_addr.s6_addr32[i] = address->s6_addr32[i] & net_mask.s6_addr32[i];
+ /* host id */
+ ipv6_temp_addr.s6_addr32[i] |= temp.s6_addr32[i] & ~net_mask.s6_addr32[i];
+ }
+
+ *address = ipv6_temp_addr;
+ return 0;
+}
+
static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
struct ipv6_stable_secret *s = &idev->cnf.stable_secret;
diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
--- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
@@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
in6_dev->if_flags |= IF_RA_RCVD;
}
+ in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
+ IF_RA_VAR_PLEN : 0;
/*
* Remember the managed/otherconf flags from most recently
* received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 1:53 ` Jakub Kicinski
@ 2020-11-13 2:01 ` Dave Hansen
0 siblings, 0 replies; 49+ messages in thread
From: Dave Hansen @ 2020-11-13 2:01 UTC (permalink / raw)
To: Jakub Kicinski
Cc: kernel test robot, Dmytro Shytyi, kuznet, yoshfuji, liuhangbin,
davem, netdev, linux-kernel, kbuild-all
On 11/12/20 5:53 PM, Jakub Kicinski wrote:
>> I do agree, though, that it's confusing *what* they reported, especially
>> if the patch in question is fixing something *else*. Rather than invent
>> a new tag, maybe a comment would suffice:
>>
>> Reported-by: kernel test robot <lkp@intel.com> # bug in earlier revision
> Fine by me, although its not common to add Reported-by tags for people
> who point out issues in review, so why add a tag for the bot?
If for no other reason, it helps Philip and team generate accurate data
on how effective and helpful the bot is. That, in turn, plays a role in
making sure that Intel keeps funding it.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V4] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 1:56 ` [PATCH net-next V4] " Dmytro Shytyi
@ 2020-11-13 12:38 ` Hideaki Yoshifuji
2020-11-13 19:09 ` Dmytro Shytyi
2020-11-13 19:36 ` [PATCH net-next V5] " Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: Hideaki Yoshifuji @ 2020-11-13 12:38 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel,
Hideaki Yoshifuji
Hi,
2020年11月13日(金) 10:57 Dmytro Shytyi <dmytro@shytyi.net>:
>
> Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> Load-Balancer and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> ---
> diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 02:30:25.552724864 +0100
> @@ -1315,10 +1322,14 @@ static int ipv6_create_tempaddr(struct i
> struct ifa6_config cfg;
> long max_desync_factor;
> struct in6_addr addr;
> - int ret = 0;
> + int ret;
> + struct in6_addr net_mask;
> + struct in6_addr temp;
> + struct in6_addr ipv6addr;
> + int i;
>
> write_lock_bh(&idev->lock);
> -
> + ret = 0;
> retry:
> in6_dev_hold(idev);
> if (idev->cnf.use_tempaddr <= 0) {
> @@ -1340,9 +1351,26 @@ retry:
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> + get_random_bytes(temp.s6_addr32, 16);
> +
> + /* tranfrom prefix len into mask */
> + ipv6_plen_to_mask(ifp->prefix_len, &net_mask);
> +
> + for (i = 0; i < 4; i++) {
> + /* network prefix */
> + ipv6addr.s6_addr32[i] = addr.s6_addr32[i] & net_mask.s6_addr32[i];
> + /* host id */
> + ipv6addr.s6_addr32[i] |= temp.s6_addr32[i] & ~net_mask.s6_addr32[i];
> + }
> +
> + memcpy(addr.s6_addr, ipv6addr.s6_addr32, 16);
>
ipv6_addr_copy() and then ipv6_addr_prefix_copy()
+ }
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2576,9 +2604,57 @@ int addrconf_prefix_rcv_add_addr(struct
> u32 addr_flags, bool sllao, bool tokenized,
> __u32 valid_lft, u32 prefered_lft)
> {
> - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + struct inet6_ifaddr *ifp = NULL;
> int create = 0;
>
> + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + struct inet6_ifaddr *result = NULL;
> + struct inet6_ifaddr *result_base = NULL;
> + struct in6_addr net_mask;
> + struct in6_addr net_prfx;
> + struct in6_addr curr_net_prfx;
> + bool prfxs_equal;
> + int i;
> +
> + result_base = result;
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> +
> + /* tranfrom prefix len into mask */
> + ipv6_plen_to_mask(pinfo->prefix_len, &net_mask);
> + /* Prepare network prefixes */
> + for (i = 0; i < 4; i++) {
> + /* Received/new network prefix */
> + net_prfx.s6_addr32[i] =
> + pinfo->prefix.s6_addr32[i] & net_mask.s6_addr32[i];
> + /* Configured/old IPv6 prefix */
> + curr_net_prfx.s6_addr32[i] =
> + ifp->addr.s6_addr32[i] & net_mask.s6_addr32[i];
> + }
> + /* Compare network prefixes */
> + prfxs_equal = 1;
> + for (i = 0; i < 4; i++) {
> + if ((net_prfx.s6_addr32[i] ^ curr_net_prfx.s6_addr32[i]) != 0)
> + prfxs_equal = 0;
> + }
ipv6_prefix_equal()
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> + if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
> + } else {
> + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + }
> +
> if (!ifp && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> struct ifa6_config cfg = {
> @@ -2781,9 +2857,35 @@ void addrconf_prefix_rcv(struct net_devi
> dev_addr_generated = true;
> }
> goto ok;
> + goto put;
> + } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
> + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + * Contact: Dmytro Shytyi.
> + */
> + memcpy(&addr, &pinfo->prefix, 16);
> + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + if (!ipv6_generate_address_variable_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + true)) {
> + addr_flags |= IFA_F_STABLE_PRIVACY;
> + goto ok;
> + }
> + } else if (!ipv6_generate_address_variable_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + false)) {
> + goto ok;
> + }
> + } else {
> + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> + pinfo->prefix_len);
> }
> - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> - pinfo->prefix_len);
> goto put;
>
> ok:
> @@ -3264,6 +3366,118 @@ retry:
> return 0;
> }
>
> +static void ipv6_plen_to_mask(int plen, struct in6_addr *net_mask)
> +{
> + int i, plen_bytes;
> + char bit_array[7] = {0b10000000,
> + 0b11000000,
> + 0b11100000,
> + 0b11110000,
> + 0b11111000,
> + 0b11111100,
> + 0b11111110};
> +
> + if (plen <= 0 || plen > 128)
> + pr_err("Unexpected plen: %d", plen);
> +
> + memset(net_mask, 0x00, sizeof(*net_mask));
> +
> + /* We set all bits == 1 of s6_addr[i] */
> + plen_bytes = plen / 8;
> + for (i = 0; i < plen_bytes; i++)
> + net_mask->s6_addr[i] = 0xff;
> +
> + /* We add bits from the bit_array to
> + * netmask starting from plen_bytes position
> + */
> + if (plen % 8)
> + net_mask->s6_addr[plen_bytes] = bit_array[(plen % 8) - 1];
> + memcpy(net_mask->s6_addr32, net_mask->s6_addr, 16);
> +}
I don't think we need this function.
If needed, we could introduce ipv6_addr_host() (like ipv6_addr_prefix())
in include/net/ipv6.h.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V4] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 12:38 ` Hideaki Yoshifuji
@ 2020-11-13 19:09 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-13 19:09 UTC (permalink / raw)
To: Hideaki Yoshifuji
Cc: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Hello,
---- On Fri, 13 Nov 2020 13:38:02 +0100 Hideaki Yoshifuji <hideaki.yoshifuji@miraclelinux.com> wrote ----
> Hi,
>
> 2020年11月13日(金) 10:57 Dmytro Shytyi <dmytro@shytyi.net>:
> >
> > Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > Load-Balancer and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > ---
> > diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> > --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> > +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 02:30:25.552724864 +0100
> > @@ -1315,10 +1322,14 @@ static int ipv6_create_tempaddr(struct i
> > struct ifa6_config cfg;
> > long max_desync_factor;
> > struct in6_addr addr;
> > - int ret = 0;
> > + int ret;
> > + struct in6_addr net_mask;
> > + struct in6_addr temp;
> > + struct in6_addr ipv6addr;
> > + int i;
> >
> > write_lock_bh(&idev->lock);
> > -
> > + ret = 0;
> > retry:
> > in6_dev_hold(idev);
> > if (idev->cnf.use_tempaddr <= 0) {
> > @@ -1340,9 +1351,26 @@ retry:
> > goto out;
> > }
> > in6_ifa_hold(ifp);
> > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > - ipv6_gen_rnd_iid(&addr);
> >
> > + if (ifp->prefix_len == 64) {
> > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > + ipv6_gen_rnd_iid(&addr);
> > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> > + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> > + get_random_bytes(temp.s6_addr32, 16);
> > +
> > + /* tranfrom prefix len into mask */
> > + ipv6_plen_to_mask(ifp->prefix_len, &net_mask);
> > +
> > + for (i = 0; i < 4; i++) {
> > + /* network prefix */
> > + ipv6addr.s6_addr32[i] = addr.s6_addr32[i] & net_mask.s6_addr32[i];
> > + /* host id */
> > + ipv6addr.s6_addr32[i] |= temp.s6_addr32[i] & ~net_mask.s6_addr32[i];
> > + }
> > +
> > + memcpy(addr.s6_addr, ipv6addr.s6_addr32, 16);
> >
>
> ipv6_addr_copy() and then ipv6_addr_prefix_copy()
[Dmytro] Understood. Migrating to ipv6_addr_prefix_copy()
> + }
> > age = (now - ifp->tstamp) / HZ;
> >
> > regen_advance = idev->cnf.regen_max_retry *
> > @@ -2576,9 +2604,57 @@ int addrconf_prefix_rcv_add_addr(struct
> > u32 addr_flags, bool sllao, bool tokenized,
> > __u32 valid_lft, u32 prefered_lft)
> > {
> > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + struct inet6_ifaddr *ifp = NULL;
> > int create = 0;
> >
> > + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + struct inet6_ifaddr *result = NULL;
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct in6_addr net_mask;
> > + struct in6_addr net_prfx;
> > + struct in6_addr curr_net_prfx;
> > + bool prfxs_equal;
> > + int i;
> > +
> > + result_base = result;
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > +
> > + /* tranfrom prefix len into mask */
> > + ipv6_plen_to_mask(pinfo->prefix_len, &net_mask);
> > + /* Prepare network prefixes */
> > + for (i = 0; i < 4; i++) {
> > + /* Received/new network prefix */
> > + net_prfx.s6_addr32[i] =
> > + pinfo->prefix.s6_addr32[i] & net_mask.s6_addr32[i];
> > + /* Configured/old IPv6 prefix */
> > + curr_net_prfx.s6_addr32[i] =
> > + ifp->addr.s6_addr32[i] & net_mask.s6_addr32[i];
> > + }
> > + /* Compare network prefixes */
> > + prfxs_equal = 1;
> > + for (i = 0; i < 4; i++) {
> > + if ((net_prfx.s6_addr32[i] ^ curr_net_prfx.s6_addr32[i]) != 0)
> > + prfxs_equal = 0;
> > + }
>
> ipv6_prefix_equal()
[Dmytro] Understood. Migrating to ipv6_prefix_equal()
>
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
> > + }
> > + rcu_read_unlock();
> > + if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
> > + } else {
> > + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + }
> > +
> > if (!ifp && valid_lft) {
> > int max_addresses = in6_dev->cnf.max_addresses;
> > struct ifa6_config cfg = {
> > @@ -2781,9 +2857,35 @@ void addrconf_prefix_rcv(struct net_devi
> > dev_addr_generated = true;
> > }
> > goto ok;
> > + goto put;
> > + } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
> > + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> > + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> > + * draft-mishra-6man-variable-slaac
> > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > + * Contact: Dmytro Shytyi.
> > + */
> > + memcpy(&addr, &pinfo->prefix, 16);
> > + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + if (!ipv6_generate_address_variable_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + true)) {
> > + addr_flags |= IFA_F_STABLE_PRIVACY;
> > + goto ok;
> > + }
> > + } else if (!ipv6_generate_address_variable_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + false)) {
> > + goto ok;
> > + }
> > + } else {
> > + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> > + pinfo->prefix_len);
> > }
> > - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> > - pinfo->prefix_len);
> > goto put;
> >
> > ok:
> > @@ -3264,6 +3366,118 @@ retry:
> > return 0;
> > }
> >
> > +static void ipv6_plen_to_mask(int plen, struct in6_addr *net_mask)
> > +{
> > + int i, plen_bytes;
> > + char bit_array[7] = {0b10000000,
> > + 0b11000000,
> > + 0b11100000,
> > + 0b11110000,
> > + 0b11111000,
> > + 0b11111100,
> > + 0b11111110};
> > +
> > + if (plen <= 0 || plen > 128)
> > + pr_err("Unexpected plen: %d", plen);
> > +
> > + memset(net_mask, 0x00, sizeof(*net_mask));
> > +
> > + /* We set all bits == 1 of s6_addr[i] */
> > + plen_bytes = plen / 8;
> > + for (i = 0; i < plen_bytes; i++)
> > + net_mask->s6_addr[i] = 0xff;
> > +
> > + /* We add bits from the bit_array to
> > + * netmask starting from plen_bytes position
> > + */
> > + if (plen % 8)
> > + net_mask->s6_addr[plen_bytes] = bit_array[(plen % 8) - 1];
> > + memcpy(net_mask->s6_addr32, net_mask->s6_addr, 16);
> > +}
>
> I don't think we need this function.
[Dmytro] Indeed.
> If needed, we could introduce ipv6_addr_host() (like ipv6_addr_prefix())
> in include/net/ipv6.h.
[Dmytro] Maybe, we will see...
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V5] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 1:56 ` [PATCH net-next V4] " Dmytro Shytyi
2020-11-13 12:38 ` Hideaki Yoshifuji
@ 2020-11-13 19:36 ` Dmytro Shytyi
2020-11-17 20:43 ` Jakub Kicinski
1 sibling, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-13 19:36 UTC (permalink / raw)
To: kuba, kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
--- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
+++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
@@ -22,6 +22,12 @@
#define IF_RS_SENT 0x10
#define IF_READY 0x80000000
+/* Variable SLAAC (Contact: Dmytro Shytyi)
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+#define IF_RA_VAR_PLEN 0x08
+
/* prefix flags */
#define IF_PREFIX_ONLINK 0x01
#define IF_PREFIX_AUTOCONF 0x02
diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
--- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
+++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
@@ -42,7 +42,9 @@ struct icmp6hdr {
struct icmpv6_nd_ra {
__u8 hop_limit;
#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 reserved:3,
+ __u8 reserved:1,
+ slaac_var_plen:1,
+ proxy:1,
router_pref:2,
home_agent:1,
other:1,
@@ -53,7 +55,9 @@ struct icmp6hdr {
other:1,
home_agent:1,
router_pref:2,
- reserved:3;
+ proxy:1,
+ slaac_var_plen:1,
+ reserved:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
@@ -78,9 +82,9 @@ struct icmp6hdr {
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
+#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
};
-
#define ICMPV6_ROUTER_PREF_LOW 0x3
#define ICMPV6_ROUTER_PREF_MEDIUM 0x0
#define ICMPV6_ROUTER_PREF_HIGH 0x1
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 19:50:04.401227310 +0100
@@ -11,6 +11,8 @@
/*
* Changes:
*
+ * Dmytro Shytyi : Variable SLAAC: SLAAC with
+ * <dmytro@shytyi.net> prefixes of arbitrary length.
* Janos Farkas : delete timer on ifdown
* <chexum@bankinf.banki.hu>
* Andi Kleen : kill double kfree on module
@@ -142,7 +144,11 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode);
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1315,10 +1321,11 @@ static int ipv6_create_tempaddr(struct i
struct ifa6_config cfg;
long max_desync_factor;
struct in6_addr addr;
- int ret = 0;
+ int ret;
+ struct in6_addr temp;
write_lock_bh(&idev->lock);
-
+ ret = 0;
retry:
in6_dev_hold(idev);
if (idev->cnf.use_tempaddr <= 0) {
@@ -1340,9 +1347,16 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+ memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+ ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
+ memcpy(addr.s6_addr, temp.s6_addr, 16);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2576,9 +2590,42 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
int create = 0;
+ if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ struct inet6_ifaddr *result = NULL;
+ struct inet6_ifaddr *result_base = NULL;
+ struct in6_addr curr_net_prfx;
+ struct in6_addr net_prfx;
+ bool prfxs_equal;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
+ ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
+ prfxs_equal =
+ ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
+
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+ } else {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2781,9 +2828,34 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ * Contact: Dmytro Shytyi.
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_generate_address_variable_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3263,6 +3335,77 @@ retry:
*address = temp;
return 0;
}
+
+static int ipv6_generate_address_variable_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static DEFINE_SPINLOCK(lock);
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+
+ struct in6_addr secret;
+ struct in6_addr temp;
+ struct net *net = dev_net(idev->dev);
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
+ *address = temp;
+ return 0;
+}
static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
--- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
@@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
in6_dev->if_flags |= IF_RA_RCVD;
}
+ in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
+ IF_RA_VAR_PLEN : 0;
/*
* Remember the managed/otherconf flags from most recently
* received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V5] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-13 19:36 ` [PATCH net-next V5] " Dmytro Shytyi
@ 2020-11-17 20:43 ` Jakub Kicinski
2020-11-18 13:41 ` Dmytro Shytyi
2020-11-19 13:37 ` [PATCH net-next V6] " Dmytro Shytyi
0 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-17 20:43 UTC (permalink / raw)
To: Dmytro Shytyi; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
On Fri, 13 Nov 2020 20:36:58 +0100 Dmytro Shytyi wrote:
> Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> Load-Balancer and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> ---
> diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
> --- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
> +++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
> @@ -22,6 +22,12 @@
> #define IF_RS_SENT 0x10
> #define IF_READY 0x80000000
>
> +/* Variable SLAAC (Contact: Dmytro Shytyi)
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + */
> +#define IF_RA_VAR_PLEN 0x08
> +
> /* prefix flags */
> #define IF_PREFIX_ONLINK 0x01
> #define IF_PREFIX_AUTOCONF 0x02
> diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
> --- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
> +++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
> @@ -42,7 +42,9 @@ struct icmp6hdr {
> struct icmpv6_nd_ra {
> __u8 hop_limit;
> #if defined(__LITTLE_ENDIAN_BITFIELD)
> - __u8 reserved:3,
> + __u8 reserved:1,
> + slaac_var_plen:1,
> + proxy:1,
What's the status of your draft? I'm not too familiar with the IETF
process, but I'm not sure we should change uAPI headers before the
draft reaches reasonable consensus.
I'd appreciate extra opinions here.
> router_pref:2,
> home_agent:1,
> other:1,
> @@ -53,7 +55,9 @@ struct icmp6hdr {
> other:1,
> home_agent:1,
> router_pref:2,
> - reserved:3;
> + proxy:1,
> + slaac_var_plen:1,
> + reserved:1;
> #else
> #error "Please fix <asm/byteorder.h>"
> #endif
> @@ -78,9 +82,9 @@ struct icmp6hdr {
> #define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
> #define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
> #define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
> +#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
> };
>
> -
> #define ICMPV6_ROUTER_PREF_LOW 0x3
> #define ICMPV6_ROUTER_PREF_MEDIUM 0x0
> #define ICMPV6_ROUTER_PREF_HIGH 0x1
> diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 19:50:04.401227310 +0100
> @@ -11,6 +11,8 @@
> /*
> * Changes:
> *
> + * Dmytro Shytyi : Variable SLAAC: SLAAC with
> + * <dmytro@shytyi.net> prefixes of arbitrary length.
Please don't add your name to those headers. We have git now,
authorship if clearly preserved.
> * Janos Farkas : delete timer on ifdown
> * <chexum@bankinf.banki.hu>
> * Andi Kleen : kill double kfree on module
> @@ -142,7 +144,11 @@ static int ipv6_count_addresses(const st
> static int ipv6_generate_stable_address(struct in6_addr *addr,
> u8 dad_count,
> const struct inet6_dev *idev);
> -
> +static int ipv6_generate_address_variable_plen(struct in6_addr *address,
> + u8 dad_count,
> + const struct inet6_dev *idev,
> + unsigned int rcvd_prfx_len,
> + bool stable_privacy_mode);
Can you reorder the code to avoid the fwd declaration?
Also please try to shorten the name of this function.
> #define IN6_ADDR_HSIZE_SHIFT 8
> #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
> /*
> @@ -1315,10 +1321,11 @@ static int ipv6_create_tempaddr(struct i
> struct ifa6_config cfg;
> long max_desync_factor;
> struct in6_addr addr;
> - int ret = 0;
> + int ret;
> + struct in6_addr temp;
Please keep the reverse xmas tree ordering of variables.
Lines should be ordered longest to shortest.
>
> write_lock_bh(&idev->lock);
> -
> + ret = 0;
Why did you decide to move the init from the definition?
> retry:
> in6_dev_hold(idev);
> if (idev->cnf.use_tempaddr <= 0) {
> @@ -1340,9 +1347,16 @@ retry:
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> + get_random_bytes(temp.s6_addr32, 16);
> + ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
> + memcpy(addr.s6_addr, temp.s6_addr, 16);
> + }
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2576,9 +2590,42 @@ int addrconf_prefix_rcv_add_addr(struct
> u32 addr_flags, bool sllao, bool tokenized,
> __u32 valid_lft, u32 prefered_lft)
> {
> - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + struct inet6_ifaddr *ifp = NULL;
> int create = 0;
>
> + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + struct inet6_ifaddr *result = NULL;
> + struct inet6_ifaddr *result_base = NULL;
> + struct in6_addr curr_net_prfx;
> + struct in6_addr net_prfx;
> + bool prfxs_equal;
> +
> + result_base = result;
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> + prfxs_equal =
> + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> +
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> + if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
Could this be a helper of its own?
> + } else {
> + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + }
> +
> if (!ifp && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> struct ifa6_config cfg = {
> @@ -2781,9 +2828,34 @@ void addrconf_prefix_rcv(struct net_devi
> dev_addr_generated = true;
> }
> goto ok;
> + } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
> + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + * Contact: Dmytro Shytyi.
> + */
> + memcpy(&addr, &pinfo->prefix, 16);
> + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + if (!ipv6_generate_address_variable_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + true)) {
> + addr_flags |= IFA_F_STABLE_PRIVACY;
> + goto ok;
> + }
> + } else if (!ipv6_generate_address_variable_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + false)) {
> + goto ok;
> + }
> + } else {
> + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> + pinfo->prefix_len);
> }
> - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> - pinfo->prefix_len);
> goto put;
>
> ok:
> @@ -3263,6 +3335,77 @@ retry:
> *address = temp;
> return 0;
> }
> +
> +static int ipv6_generate_address_variable_plen(struct in6_addr *address,
> + u8 dad_count,
> + const struct inet6_dev *idev,
> + unsigned int rcvd_prfx_len,
> + bool stable_privacy_mode)
> +{
> + static DEFINE_SPINLOCK(lock);
> + static __u32 digest[SHA1_DIGEST_WORDS];
> + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> +
> + static union {
> + char __data[SHA1_BLOCK_SIZE];
> + struct {
> + struct in6_addr secret;
> + __be32 prefix[2];
> + unsigned char hwaddr[MAX_ADDR_LEN];
> + u8 dad_count;
> + } __packed;
> + } data;
> +
> + struct in6_addr secret;
> + struct in6_addr temp;
> + struct net *net = dev_net(idev->dev);
Please dont add empty lines between variable declarations.
> + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> +
> + if (stable_privacy_mode) {
> + if (idev->cnf.stable_secret.initialized)
> + secret = idev->cnf.stable_secret.secret;
> + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> + else
> + return -1;
> + }
> +
> +retry:
> + spin_lock_bh(&lock);
> + if (stable_privacy_mode) {
> + sha1_init(digest);
> + memset(&data, 0, sizeof(data));
> + memset(workspace, 0, sizeof(workspace));
> + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> + data.prefix[0] = address->s6_addr32[0];
> + data.prefix[1] = address->s6_addr32[1];
> + data.secret = secret;
> + data.dad_count = dad_count;
> +
> + sha1_transform(digest, data.__data, workspace);
> +
> + temp = *address;
> + temp.s6_addr32[0] = (__force __be32)digest[0];
> + temp.s6_addr32[1] = (__force __be32)digest[1];
> + temp.s6_addr32[2] = (__force __be32)digest[2];
> + temp.s6_addr32[3] = (__force __be32)digest[3];
> + } else {
> + temp = *address;
> + get_random_bytes(temp.s6_addr32, 16);
> + }
> + spin_unlock_bh(&lock);
> +
> + if (ipv6_reserved_interfaceid(temp)) {
> + dad_count++;
> + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> + return -1;
> + goto retry;
> + }
> + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> + *address = temp;
> + return 0;
> +}
>
> static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
> {
> diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
> --- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
> +++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
> @@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
> in6_dev->if_flags |= IF_RA_RCVD;
> }
>
> + in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
> + IF_RA_VAR_PLEN : 0;
> /*
> * Remember the managed/otherconf flags from most recently
> * received RA message (RFC 2462) -- yoshfuji
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V5] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-17 20:43 ` Jakub Kicinski
@ 2020-11-18 13:41 ` Dmytro Shytyi
2020-11-18 15:50 ` Jakub Kicinski
2020-11-19 13:37 ` [PATCH net-next V6] " Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-18 13:41 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Hello,
---- On Tue, 17 Nov 2020 21:43:48 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> On Fri, 13 Nov 2020 20:36:58 +0100 Dmytro Shytyi wrote:
> > Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > Load-Balancer and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > ---
> > diff -rupN net-next-5.10.0-rc2/include/net/if_inet6.h net-next-patch-5.10.0-rc2/include/net/if_inet6.h
> > --- net-next-5.10.0-rc2/include/net/if_inet6.h 2020-11-10 08:46:00.195180579 +0100
> > +++ net-next-patch-5.10.0-rc2/include/net/if_inet6.h 2020-11-11 18:11:05.627550135 +0100
> > @@ -22,6 +22,12 @@
> > #define IF_RS_SENT 0x10
> > #define IF_READY 0x80000000
> >
> > +/* Variable SLAAC (Contact: Dmytro Shytyi)
> > + * draft-mishra-6man-variable-slaac
> > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > + */
> > +#define IF_RA_VAR_PLEN 0x08
> > +
> > /* prefix flags */
> > #define IF_PREFIX_ONLINK 0x01
> > #define IF_PREFIX_AUTOCONF 0x02
> > diff -rupN net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h
> > --- net-next-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-10 08:46:00.351849525 +0100
> > +++ net-next-patch-5.10.0-rc2/include/uapi/linux/icmpv6.h 2020-11-11 18:11:05.627550135 +0100
> > @@ -42,7 +42,9 @@ struct icmp6hdr {
> > struct icmpv6_nd_ra {
> > __u8 hop_limit;
> > #if defined(__LITTLE_ENDIAN_BITFIELD)
> > - __u8 reserved:3,
> > + __u8 reserved:1,
> > + slaac_var_plen:1,
> > + proxy:1,
>
> What's the status of your draft? I'm not too familiar with the IETF
> process, but I'm not sure we should change uAPI headers before the
> draft reaches reasonable consensus.
>
> I'd appreciate extra opinions here.
Okay, we may avoid modification of the uAPI headers as plen (prefix length !=64) itself serves as a flag to activate the "Variable SLAAC"
I will modify the patch accordingly.
> > router_pref:2,
> > home_agent:1,
> > other:1,
> > @@ -53,7 +55,9 @@ struct icmp6hdr {
> > other:1,
> > home_agent:1,
> > router_pref:2,
> > - reserved:3;
> > + proxy:1,
> > + slaac_var_plen:1,
> > + reserved:1;
> > #else
> > #error "Please fix <asm/byteorder.h>"
> > #endif
> > @@ -78,9 +82,9 @@ struct icmp6hdr {
> > #define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
> > #define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
> > #define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
> > +#define icmp6_slaac_var_plen icmp6_dataun.u_nd_ra.slaac_var_plen
> > };
> >
> > -
> > #define ICMPV6_ROUTER_PREF_LOW 0x3
> > #define ICMPV6_ROUTER_PREF_MEDIUM 0x0
> > #define ICMPV6_ROUTER_PREF_HIGH 0x1
> > diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> > --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> > +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-13 19:50:04.401227310 +0100
> > @@ -11,6 +11,8 @@
> > /*
> > * Changes:
> > *
> > + * Dmytro Shytyi : Variable SLAAC: SLAAC with
> > + * <dmytro@shytyi.net> prefixes of arbitrary length.
>
> Please don't add your name to those headers. We have git now,
> authorship if clearly preserved.
Understood.
> > * Janos Farkas : delete timer on ifdown
> > * <chexum@bankinf.banki.hu>
> > * Andi Kleen : kill double kfree on module
> > @@ -142,7 +144,11 @@ static int ipv6_count_addresses(const st
> > static int ipv6_generate_stable_address(struct in6_addr *addr,
> > u8 dad_count,
> > const struct inet6_dev *idev);
> > -
> > +static int ipv6_generate_address_variable_plen(struct in6_addr *address,
> > + u8 dad_count,
> > + const struct inet6_dev *idev,
> > + unsigned int rcvd_prfx_len,
> > + bool stable_privacy_mode);
>
> Can you reorder the code to avoid the fwd declaration?
> Also please try to shorten the name of this function.
Understood.
> > #define IN6_ADDR_HSIZE_SHIFT 8
> > #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
> > /*
> > @@ -1315,10 +1321,11 @@ static int ipv6_create_tempaddr(struct i
> > struct ifa6_config cfg;
> > long max_desync_factor;
> > struct in6_addr addr;
> > - int ret = 0;
> > + int ret;
> > + struct in6_addr temp;
>
> Please keep the reverse xmas tree ordering of variables.
> Lines should be ordered longest to shortest.
Understood.
> >
> > write_lock_bh(&idev->lock);
> > -
> > + ret = 0;
>
> Why did you decide to move the init from the definition?
>
> > retry:
> > in6_dev_hold(idev);
> > if (idev->cnf.use_tempaddr <= 0) {
> > @@ -1340,9 +1347,16 @@ retry:
> > goto out;
> > }
> > in6_ifa_hold(ifp);
> > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > - ipv6_gen_rnd_iid(&addr);
> >
> > + if (ifp->prefix_len == 64) {
> > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > + ipv6_gen_rnd_iid(&addr);
> > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> > + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> > + get_random_bytes(temp.s6_addr32, 16);
> > + ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
> > + memcpy(addr.s6_addr, temp.s6_addr, 16);
> > + }
> > age = (now - ifp->tstamp) / HZ;
> >
> > regen_advance = idev->cnf.regen_max_retry *
> > @@ -2576,9 +2590,42 @@ int addrconf_prefix_rcv_add_addr(struct
> > u32 addr_flags, bool sllao, bool tokenized,
> > __u32 valid_lft, u32 prefered_lft)
> > {
> > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + struct inet6_ifaddr *ifp = NULL;
> > int create = 0;
> >
> > + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + struct inet6_ifaddr *result = NULL;
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct in6_addr curr_net_prfx;
> > + struct in6_addr net_prfx;
> > + bool prfxs_equal;
> > +
> > + result_base = result;
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> > + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> > + prfxs_equal =
> > + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> > +
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
> > + }
> > + rcu_read_unlock();
> > + if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
>
> Could this be a helper of its own?
Explain the thought please. It is not clear for me.
> > + } else {
> > + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + }
> > +
> > if (!ifp && valid_lft) {
> > int max_addresses = in6_dev->cnf.max_addresses;
> > struct ifa6_config cfg = {
> > @@ -2781,9 +2828,34 @@ void addrconf_prefix_rcv(struct net_devi
> > dev_addr_generated = true;
> > }
> > goto ok;
> > + } else if (((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN) &&
> > + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> > + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> > + * draft-mishra-6man-variable-slaac
> > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > + * Contact: Dmytro Shytyi.
> > + */
> > + memcpy(&addr, &pinfo->prefix, 16);
> > + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + if (!ipv6_generate_address_variable_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + true)) {
> > + addr_flags |= IFA_F_STABLE_PRIVACY;
> > + goto ok;
> > + }
> > + } else if (!ipv6_generate_address_variable_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + false)) {
> > + goto ok;
> > + }
> > + } else {
> > + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> > + pinfo->prefix_len);
> > }
> > - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> > - pinfo->prefix_len);
> > goto put;
> >
> > ok:
> > @@ -3263,6 +3335,77 @@ retry:
> > *address = temp;
> > return 0;
> > }
> > +
> > +static int ipv6_generate_address_variable_plen(struct in6_addr *address,
> > + u8 dad_count,
> > + const struct inet6_dev *idev,
> > + unsigned int rcvd_prfx_len,
> > + bool stable_privacy_mode)
> > +{
> > + static DEFINE_SPINLOCK(lock);
> > + static __u32 digest[SHA1_DIGEST_WORDS];
> > + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> > +
> > + static union {
> > + char __data[SHA1_BLOCK_SIZE];
> > + struct {
> > + struct in6_addr secret;
> > + __be32 prefix[2];
> > + unsigned char hwaddr[MAX_ADDR_LEN];
> > + u8 dad_count;
> > + } __packed;
> > + } data;
> > +
> > + struct in6_addr secret;
> > + struct in6_addr temp;
> > + struct net *net = dev_net(idev->dev);
>
> Please dont add empty lines between variable declarations.
Understood.
> > + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> > +
> > + if (stable_privacy_mode) {
> > + if (idev->cnf.stable_secret.initialized)
> > + secret = idev->cnf.stable_secret.secret;
> > + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> > + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> > + else
> > + return -1;
> > + }
> > +
> > +retry:
> > + spin_lock_bh(&lock);
> > + if (stable_privacy_mode) {
> > + sha1_init(digest);
> > + memset(&data, 0, sizeof(data));
> > + memset(workspace, 0, sizeof(workspace));
> > + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> > + data.prefix[0] = address->s6_addr32[0];
> > + data.prefix[1] = address->s6_addr32[1];
> > + data.secret = secret;
> > + data.dad_count = dad_count;
> > +
> > + sha1_transform(digest, data.__data, workspace);
> > +
> > + temp = *address;
> > + temp.s6_addr32[0] = (__force __be32)digest[0];
> > + temp.s6_addr32[1] = (__force __be32)digest[1];
> > + temp.s6_addr32[2] = (__force __be32)digest[2];
> > + temp.s6_addr32[3] = (__force __be32)digest[3];
> > + } else {
> > + temp = *address;
> > + get_random_bytes(temp.s6_addr32, 16);
> > + }
> > + spin_unlock_bh(&lock);
> > +
> > + if (ipv6_reserved_interfaceid(temp)) {
> > + dad_count++;
> > + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> > + return -1;
> > + goto retry;
> > + }
> > + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> > + *address = temp;
> > + return 0;
> > +}
> >
> > static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
> > {
> > diff -rupN net-next-5.10.0-rc2/net/ipv6/ndisc.c net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c
> > --- net-next-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-10 08:46:01.091860289 +0100
> > +++ net-next-patch-5.10.0-rc2/net/ipv6/ndisc.c 2020-11-11 18:11:05.630883513 +0100
> > @@ -1244,6 +1244,8 @@ static void ndisc_router_discovery(struc
> > in6_dev->if_flags |= IF_RA_RCVD;
> > }
> >
> > + in6_dev->if_flags |= ra_msg->icmph.icmp6_slaac_var_plen ?
> > + IF_RA_VAR_PLEN : 0;
> > /*
> > * Remember the managed/otherconf flags from most recently
> > * received RA message (RFC 2462) -- yoshfuji
>
>
Best,
Dmytro SHYTYI.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V5] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-18 13:41 ` Dmytro Shytyi
@ 2020-11-18 15:50 ` Jakub Kicinski
2020-11-18 15:56 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-18 15:50 UTC (permalink / raw)
To: Dmytro Shytyi; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
On Wed, 18 Nov 2020 14:41:03 +0100 Dmytro Shytyi wrote:
> > > @@ -2576,9 +2590,42 @@ int addrconf_prefix_rcv_add_addr(struct
> > > u32 addr_flags, bool sllao, bool tokenized,
> > > __u32 valid_lft, u32 prefered_lft)
> > > {
> > > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > > + struct inet6_ifaddr *ifp = NULL;
> > > int create = 0;
> > >
> > > + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> > > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > > + struct inet6_ifaddr *result = NULL;
> > > + struct inet6_ifaddr *result_base = NULL;
> > > + struct in6_addr curr_net_prfx;
> > > + struct in6_addr net_prfx;
> > > + bool prfxs_equal;
> > > +
> > > + result_base = result;
> > > + rcu_read_lock();
> > > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > > + continue;
> > > + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> > > + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> > > + prfxs_equal =
> > > + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> > > +
> > > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > > + result = ifp;
> > > + in6_ifa_hold(ifp);
> > > + break;
> > > + }
> > > + }
> > > + rcu_read_unlock();
> > > + if (result_base != result)
> > > + ifp = result;
> > > + else
> > > + ifp = NULL;
> >
> > Could this be a helper of its own?
>
> Explain the thought please. It is not clear for me.
At the look of it the code under this if statement looks relatively
self-contained, and has quite a few local variables. Rather than making
the surrounding function longer would it be possible to factor it out
into a helper function?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V5] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-18 15:50 ` Jakub Kicinski
@ 2020-11-18 15:56 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-18 15:56 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: kuznet, yoshfuji, liuhangbin, davem, netdev, linux-kernel
Hello,
---- On Wed, 18 Nov 2020 16:50:27 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> On Wed, 18 Nov 2020 14:41:03 +0100 Dmytro Shytyi wrote:
> > > > @@ -2576,9 +2590,42 @@ int addrconf_prefix_rcv_add_addr(struct
> > > > u32 addr_flags, bool sllao, bool tokenized,
> > > > __u32 valid_lft, u32 prefered_lft)
> > > > {
> > > > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > > > + struct inet6_ifaddr *ifp = NULL;
> > > > int create = 0;
> > > >
> > > > + if ((in6_dev->if_flags & IF_RA_VAR_PLEN) == IF_RA_VAR_PLEN &&
> > > > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > > > + struct inet6_ifaddr *result = NULL;
> > > > + struct inet6_ifaddr *result_base = NULL;
> > > > + struct in6_addr curr_net_prfx;
> > > > + struct in6_addr net_prfx;
> > > > + bool prfxs_equal;
> > > > +
> > > > + result_base = result;
> > > > + rcu_read_lock();
> > > > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > > > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > > > + continue;
> > > > + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> > > > + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> > > > + prfxs_equal =
> > > > + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> > > > +
> > > > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > > > + result = ifp;
> > > > + in6_ifa_hold(ifp);
> > > > + break;
> > > > + }
> > > > + }
> > > > + rcu_read_unlock();
> > > > + if (result_base != result)
> > > > + ifp = result;
> > > > + else
> > > > + ifp = NULL;
> > >
> > > Could this be a helper of its own?
> >
> > Explain the thought please. It is not clear for me.
>
> At the look of it the code under this if statement looks relatively
> self-contained, and has quite a few local variables. Rather than making
> the surrounding function longer would it be possible to factor it out
> into a helper function?
>
Understood.
Thanks.
Best regards,
Dmytro SHYTYI.
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V6] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-17 20:43 ` Jakub Kicinski
2020-11-18 13:41 ` Dmytro Shytyi
@ 2020-11-19 13:37 ` Dmytro Shytyi
2020-11-19 18:44 ` Jakub Kicinski
1 sibling, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-19 13:37 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-19 12:27:58.252392820 +0100
@@ -142,7 +142,6 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1315,6 +1314,7 @@ static int ipv6_create_tempaddr(struct i
struct ifa6_config cfg;
long max_desync_factor;
struct in6_addr addr;
+ struct in6_addr temp;
int ret = 0;
write_lock_bh(&idev->lock);
@@ -1340,9 +1340,16 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+ memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+ ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
+ memcpy(addr.s6_addr, temp.s6_addr, 16);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2569,6 +2576,41 @@ static bool is_addr_mode_generate_stable
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}
+struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result_base = NULL;
+ struct inet6_ifaddr *result = NULL;
+ struct in6_addr curr_net_prfx;
+ struct in6_addr net_prfx;
+ bool prfxs_equal;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
+ ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
+ prfxs_equal =
+ ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+
+ return ifp;
+}
+
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
const struct prefix_info *pinfo,
struct inet6_dev *in6_dev,
@@ -2576,9 +2618,17 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
+ int plen = pinfo->prefix_len;
int create = 0;
+ if (plen > 0 && plen <= 128 && plen != 64 &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
+ } else if (plen == 64) {
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ }
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2657,6 +2707,91 @@ int addrconf_prefix_rcv_add_addr(struct
}
EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
+static bool ipv6_reserved_interfaceid(struct in6_addr address)
+{
+ if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0x02005eff) &&
+ ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0xfdffffff) &&
+ ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
+ return true;
+
+ return false;
+}
+
+static int ipv6_gen_addr_var_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ struct net *net = dev_net(idev->dev);
+ static DEFINE_SPINLOCK(lock);
+ struct in6_addr secret;
+ struct in6_addr temp;
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
+ *address = temp;
+ return 0;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2781,9 +2916,33 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ } else if (pinfo->prefix_len != 64 &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3186,22 +3345,6 @@ void addrconf_add_linklocal(struct inet6
}
EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
-static bool ipv6_reserved_interfaceid(struct in6_addr address)
-{
- if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
- return true;
-
- if (address.s6_addr32[2] == htonl(0x02005eff) &&
- ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
- return true;
-
- if (address.s6_addr32[2] == htonl(0xfdffffff) &&
- ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
- return true;
-
- return false;
-}
-
static int ipv6_generate_stable_address(struct in6_addr *address,
u8 dad_count,
const struct inet6_dev *idev)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V6] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-19 13:37 ` [PATCH net-next V6] " Dmytro Shytyi
@ 2020-11-19 18:44 ` Jakub Kicinski
2020-11-19 19:31 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-19 18:44 UTC (permalink / raw)
To: Dmytro Shytyi; +Cc: yoshfuji, kuznet, liuhangbin, davem, netdev, linux-kernel
On Thu, 19 Nov 2020 14:37:35 +0100 Dmytro Shytyi wrote:
> +struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result_base = NULL;
> + struct inet6_ifaddr *result = NULL;
> + struct in6_addr curr_net_prfx;
> + struct in6_addr net_prfx;
> + bool prfxs_equal;
> +
> + result_base = result;
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> + prfxs_equal =
> + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> + if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
> +
> + return ifp;
> +}
Thanks for adding the helper! Looks like it needs a touch up:
net/ipv6/addrconf.c:2579:22: warning: no previous prototype for ‘ipv6_cmp_rcvd_prsnt_prfxs’ [-Wmissing-prototypes]
2579 | struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
net/ipv6/addrconf.c:2579:21: warning: symbol 'ipv6_cmp_rcvd_prsnt_prfxs' was not declared. Should it be static?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V6] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-19 18:44 ` Jakub Kicinski
@ 2020-11-19 19:31 ` Dmytro Shytyi
2020-11-20 1:20 ` Jakub Kicinski
2020-11-20 9:26 ` [PATCH net-next V7] " Dmytro Shytyi
0 siblings, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-19 19:31 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: yoshfuji, kuznet, liuhangbin, davem, netdev, linux-kernel
---- On Thu, 19 Nov 2020 19:44:13 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> On Thu, 19 Nov 2020 14:37:35 +0100 Dmytro Shytyi wrote:
> > +struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > + struct inet6_dev *in6_dev,
> > + struct net *net,
> > + const struct prefix_info *pinfo)
> > +{
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct inet6_ifaddr *result = NULL;
> > + struct in6_addr curr_net_prfx;
> > + struct in6_addr net_prfx;
> > + bool prfxs_equal;
> > +
> > + result_base = result;
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> > + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> > + prfxs_equal =
> > + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
> > + }
> > + rcu_read_unlock();
> > + if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
> > +
> > + return ifp;
> > +}
>
> Thanks for adding the helper! Looks like it needs a touch up:
Understood. Thank you for pointing this out. I think I did not catch this warning as my Makefile didn't include "-Wmissing-prototypes"
> net/ipv6/addrconf.c:2579:22: warning: no previous prototype for ‘ipv6_cmp_rcvd_prsnt_prfxs’ [-Wmissing-prototypes]
> 2579 | struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> | ^~~~~~~~~~~~~~~~~~~~~~~~~
> net/ipv6/addrconf.c:2579:21: warning: symbol 'ipv6_cmp_rcvd_prsnt_prfxs' was not declared. Should it be static?
>
Hideaki Yoshifuji helped to improve this patch with suggestions. @Hideaki, should I add "Reported-by" tag in this case?
Jakub Kicinski also helped to find errors and help with improvement. @Jakub, should I add "Reported-by" tag in this case?
Thanks,
Dmytro SHYTYI
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V6] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-19 19:31 ` Dmytro Shytyi
@ 2020-11-20 1:20 ` Jakub Kicinski
2020-11-20 9:26 ` [PATCH net-next V7] " Dmytro Shytyi
1 sibling, 0 replies; 49+ messages in thread
From: Jakub Kicinski @ 2020-11-20 1:20 UTC (permalink / raw)
To: Dmytro Shytyi; +Cc: yoshfuji, kuznet, liuhangbin, davem, netdev, linux-kernel
On Thu, 19 Nov 2020 20:31:41 +0100 Dmytro Shytyi wrote:
> > Thanks for adding the helper! Looks like it needs a touch up:
>
> Understood. Thank you for pointing this out. I think I did not catch this warning as my Makefile didn't include "-Wmissing-prototypes"
>
> > net/ipv6/addrconf.c:2579:22: warning: no previous prototype for ‘ipv6_cmp_rcvd_prsnt_prfxs’ [-Wmissing-prototypes]
> > 2579 | struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > | ^~~~~~~~~~~~~~~~~~~~~~~~~
> > net/ipv6/addrconf.c:2579:21: warning: symbol 'ipv6_cmp_rcvd_prsnt_prfxs' was not declared. Should it be static?
> >
>
> Hideaki Yoshifuji helped to improve this patch with suggestions. @Hideaki, should I add "Reported-by" tag in this case?
> Jakub Kicinski also helped to find errors and help with improvement. @Jakub, should I add "Reported-by" tag in this case?
No need for a tag for me, it would be great if Hideaki was
willing to provide his acked-by or reviewed-by though :)
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V7] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-19 19:31 ` Dmytro Shytyi
2020-11-20 1:20 ` Jakub Kicinski
@ 2020-11-20 9:26 ` Dmytro Shytyi
2020-11-23 13:26 ` Hideaki Yoshifuji
2020-12-09 3:27 ` [PATCH net-next V8] " Dmytro Shytyi
1 sibling, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-20 9:26 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel
Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
--- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
+++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-19 21:26:39.770872898 +0100
@@ -142,7 +142,6 @@ static int ipv6_count_addresses(const st
static int ipv6_generate_stable_address(struct in6_addr *addr,
u8 dad_count,
const struct inet6_dev *idev);
-
#define IN6_ADDR_HSIZE_SHIFT 8
#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
/*
@@ -1315,6 +1314,7 @@ static int ipv6_create_tempaddr(struct i
struct ifa6_config cfg;
long max_desync_factor;
struct in6_addr addr;
+ struct in6_addr temp;
int ret = 0;
write_lock_bh(&idev->lock);
@@ -1340,9 +1340,16 @@ retry:
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
+ memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
+ get_random_bytes(temp.s6_addr32, 16);
+ ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
+ memcpy(addr.s6_addr, temp.s6_addr, 16);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2569,6 +2576,41 @@ static bool is_addr_mode_generate_stable
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}
+static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result_base = NULL;
+ struct inet6_ifaddr *result = NULL;
+ struct in6_addr curr_net_prfx;
+ struct in6_addr net_prfx;
+ bool prfxs_equal;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
+ ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
+ prfxs_equal =
+ ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+
+ return ifp;
+}
+
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
const struct prefix_info *pinfo,
struct inet6_dev *in6_dev,
@@ -2576,9 +2618,16 @@ int addrconf_prefix_rcv_add_addr(struct
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
+ int plen = pinfo->prefix_len;
int create = 0;
+ if (plen > 0 && plen <= 128 && plen != 64 &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY)
+ ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
+ else
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2657,6 +2706,91 @@ int addrconf_prefix_rcv_add_addr(struct
}
EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
+static bool ipv6_reserved_interfaceid(struct in6_addr address)
+{
+ if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0x02005eff) &&
+ ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0xfdffffff) &&
+ ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
+ return true;
+
+ return false;
+}
+
+static int ipv6_gen_addr_var_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ struct net *net = dev_net(idev->dev);
+ static DEFINE_SPINLOCK(lock);
+ struct in6_addr secret;
+ struct in6_addr temp;
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp = *address;
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ temp = *address;
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
+ *address = temp;
+ return 0;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2781,9 +2915,33 @@ void addrconf_prefix_rcv(struct net_devi
dev_addr_generated = true;
}
goto ok;
+ } else if (pinfo->prefix_len != 64 &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3186,22 +3344,6 @@ void addrconf_add_linklocal(struct inet6
}
EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
-static bool ipv6_reserved_interfaceid(struct in6_addr address)
-{
- if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
- return true;
-
- if (address.s6_addr32[2] == htonl(0x02005eff) &&
- ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
- return true;
-
- if (address.s6_addr32[2] == htonl(0xfdffffff) &&
- ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
- return true;
-
- return false;
-}
-
static int ipv6_generate_stable_address(struct in6_addr *address,
u8 dad_count,
const struct inet6_dev *idev)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V7] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-20 9:26 ` [PATCH net-next V7] " Dmytro Shytyi
@ 2020-11-23 13:26 ` Hideaki Yoshifuji
2020-11-27 16:54 ` Dmytro Shytyi
2020-12-09 3:27 ` [PATCH net-next V8] " Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: Hideaki Yoshifuji @ 2020-11-23 13:26 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel, Hideaki Yoshifuji
Hi,
2020年11月20日(金) 18:28 Dmytro Shytyi <dmytro@shytyi.net>:
>
> Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> Load-Balancer and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> ---
> diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-19 21:26:39.770872898 +0100
> @@ -142,7 +142,6 @@ static int ipv6_count_addresses(const st
> static int ipv6_generate_stable_address(struct in6_addr *addr,
> u8 dad_count,
> const struct inet6_dev *idev);
> -
Do not remove this line.
> #define IN6_ADDR_HSIZE_SHIFT 8
> #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
> /*
> @@ -1315,6 +1314,7 @@ static int ipv6_create_tempaddr(struct i
> struct ifa6_config cfg;
> long max_desync_factor;
> struct in6_addr addr;
> + struct in6_addr temp;
> int ret = 0;
>
> write_lock_bh(&idev->lock);
> @@ -1340,9 +1340,16 @@ retry:
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> + get_random_bytes(temp.s6_addr32, 16);
> + ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
> + memcpy(addr.s6_addr, temp.s6_addr, 16);
> + }
I do not understand why you are copying many times.
ipv6_addr_copy(), get_random_bytes(), and then ipv6_addr_prefix_copy
is enough, no?
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2569,6 +2576,41 @@ static bool is_addr_mode_generate_stable
> idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> }
>
> +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result_base = NULL;
> + struct inet6_ifaddr *result = NULL;
> + struct in6_addr curr_net_prfx;
> + struct in6_addr net_prfx;
> + bool prfxs_equal;
> +
> + result_base = result;
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> + prfxs_equal =
> + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
I guess we can compare them with ipv6_prefix_equal()
directly because the code assumes "pinfo->prefix_len" and ifp->prefix_len are
equal.
> + }
> + rcu_read_unlock();
> + if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
> +
> + return ifp;
> +}
> +
> int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> const struct prefix_info *pinfo,
> struct inet6_dev *in6_dev,
> @@ -2576,9 +2618,16 @@ int addrconf_prefix_rcv_add_addr(struct
> u32 addr_flags, bool sllao, bool tokenized,
> __u32 valid_lft, u32 prefered_lft)
> {
> - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + struct inet6_ifaddr *ifp = NULL;
> + int plen = pinfo->prefix_len;
> int create = 0;
>
> + if (plen > 0 && plen <= 128 && plen != 64 &&
> + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY)
> + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> + else
> + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> +
> if (!ifp && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> struct ifa6_config cfg = {
I am wondering if we should enable this feature by default at this moment
because the spec is personal internet draft and some test suites might
consider this feature violates standards.
> @@ -2657,6 +2706,91 @@ int addrconf_prefix_rcv_add_addr(struct
> }
> EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
>
> +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> +{
> + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> + return true;
> +
> + return false;
> +}
> +
> +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> + u8 dad_count,
> + const struct inet6_dev *idev,
> + unsigned int rcvd_prfx_len,
> + bool stable_privacy_mode)
> +{
> + static union {
> + char __data[SHA1_BLOCK_SIZE];
> + struct {
> + struct in6_addr secret;
> + __be32 prefix[2];
> + unsigned char hwaddr[MAX_ADDR_LEN];
> + u8 dad_count;
> + } __packed;
> + } data;
> + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> + static __u32 digest[SHA1_DIGEST_WORDS];
> + struct net *net = dev_net(idev->dev);
> + static DEFINE_SPINLOCK(lock);
> + struct in6_addr secret;
> + struct in6_addr temp;
> +
> + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> +
> + if (stable_privacy_mode) {
> + if (idev->cnf.stable_secret.initialized)
> + secret = idev->cnf.stable_secret.secret;
> + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> + else
> + return -1;
> + }
> +
> +retry:
> + spin_lock_bh(&lock);
> + if (stable_privacy_mode) {
> + sha1_init(digest);
> + memset(&data, 0, sizeof(data));
> + memset(workspace, 0, sizeof(workspace));
> + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> + data.prefix[0] = address->s6_addr32[0];
> + data.prefix[1] = address->s6_addr32[1];
> + data.secret = secret;
> + data.dad_count = dad_count;
> +
> + sha1_transform(digest, data.__data, workspace);
> +
> + temp = *address;
> + temp.s6_addr32[0] = (__force __be32)digest[0];
> + temp.s6_addr32[1] = (__force __be32)digest[1];
> + temp.s6_addr32[2] = (__force __be32)digest[2];
> + temp.s6_addr32[3] = (__force __be32)digest[3];
I do not understand why you copy *address and then overwrite
by digest?
> + } else {
> + temp = *address;
> + get_random_bytes(temp.s6_addr32, 16);
> + }
> + spin_unlock_bh(&lock);
> +
> + if (ipv6_reserved_interfaceid(temp)) {
> + dad_count++;
> + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> + return -1;
> + goto retry;
> + }
> + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> + *address = temp;
> + return 0;
> +}
> +
> void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> {
> struct prefix_info *pinfo;
> @@ -2781,9 +2915,33 @@ void addrconf_prefix_rcv(struct net_devi
> dev_addr_generated = true;
> }
> goto ok;
> + } else if (pinfo->prefix_len != 64 &&
> + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + */
> + memcpy(&addr, &pinfo->prefix, 16);
> + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + true)) {
> + addr_flags |= IFA_F_STABLE_PRIVACY;
> + goto ok;
> + }
> + } else if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + false)) {
> + goto ok;
> + }
> + } else {
> + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> + pinfo->prefix_len);
> }
> - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> - pinfo->prefix_len);
> goto put;
>
> ok:
> @@ -3186,22 +3344,6 @@ void addrconf_add_linklocal(struct inet6
> }
> EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
>
> -static bool ipv6_reserved_interfaceid(struct in6_addr address)
> -{
> - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> - return true;
> -
> - if (address.s6_addr32[2] == htonl(0x02005eff) &&
> - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> - return true;
> -
> - if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> - return true;
> -
> - return false;
> -}
> -
> static int ipv6_generate_stable_address(struct in6_addr *address,
> u8 dad_count,
> const struct inet6_dev *idev)
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V7] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-23 13:26 ` Hideaki Yoshifuji
@ 2020-11-27 16:54 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-11-27 16:54 UTC (permalink / raw)
To: Hideaki Yoshifuji
Cc: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel
Hello,
---- On Mon, 23 Nov 2020 14:26:27 +0100 Hideaki Yoshifuji <hideaki.yoshifuji@miraclelinux.com> wrote ----
> Hi,
>
> 2020年11月20日(金) 18:28 Dmytro Shytyi <dmytro@shytyi.net>:
> >
> > Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > Load-Balancer and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > ---
> > diff -rupN net-next-5.10.0-rc2/net/ipv6/addrconf.c net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c
> > --- net-next-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-10 08:46:01.075193379 +0100
> > +++ net-next-patch-5.10.0-rc2/net/ipv6/addrconf.c 2020-11-19 21:26:39.770872898 +0100
> > @@ -142,7 +142,6 @@ static int ipv6_count_addresses(const st
> > static int ipv6_generate_stable_address(struct in6_addr *addr,
> > u8 dad_count,
> > const struct inet6_dev *idev);
> > -
>
> Do not remove this line.
[Dmytro]
Understood.
> > #define IN6_ADDR_HSIZE_SHIFT 8
> > #define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT)
> > /*
> > @@ -1315,6 +1314,7 @@ static int ipv6_create_tempaddr(struct i
> > struct ifa6_config cfg;
> > long max_desync_factor;
> > struct in6_addr addr;
> > + struct in6_addr temp;
> > int ret = 0;
> >
> > write_lock_bh(&idev->lock);
> > @@ -1340,9 +1340,16 @@ retry:
> > goto out;
> > }
> > in6_ifa_hold(ifp);
> > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > - ipv6_gen_rnd_iid(&addr);
> >
> > + if (ifp->prefix_len == 64) {
> > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > + ipv6_gen_rnd_iid(&addr);
> > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
> > + memcpy(addr.s6_addr32, ifp->addr.s6_addr, 16);
> > + get_random_bytes(temp.s6_addr32, 16);
> > + ipv6_addr_prefix_copy(&temp, &addr, ifp->prefix_len);
> > + memcpy(addr.s6_addr, temp.s6_addr, 16);
> > + }
>
> I do not understand why you are copying many times.
> ipv6_addr_copy(), get_random_bytes(), and then ipv6_addr_prefix_copy
> is enough, no?
[Dmytro]
I do not see any definition of ipv6_addr_copy() in v5.10-rc5.
Indeed we can try do "if case" something like this:
if (ifp->prefix_len > 0 && ifp->prefix_len <= 128) {
get_random_bytes(addr.s6_addr, 16);
ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
}
> > age = (now - ifp->tstamp) / HZ;
> >
> > regen_advance = idev->cnf.regen_max_retry *
> > @@ -2569,6 +2576,41 @@ static bool is_addr_mode_generate_stable
> > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > }
> >
> > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > + struct inet6_dev *in6_dev,
> > + struct net *net,
> > + const struct prefix_info *pinfo)
> > +{
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct inet6_ifaddr *result = NULL;
> > + struct in6_addr curr_net_prfx;
> > + struct in6_addr net_prfx;
> > + bool prfxs_equal;
> > +
> > + result_base = result;
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > + ipv6_addr_prefix_copy(&net_prfx, &pinfo->prefix, pinfo->prefix_len);
> > + ipv6_addr_prefix_copy(&curr_net_prfx, &ifp->addr, pinfo->prefix_len);
> > + prfxs_equal =
> > + ipv6_prefix_equal(&net_prfx, &curr_net_prfx, pinfo->prefix_len);
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
>
> I guess we can compare them with ipv6_prefix_equal()
> directly because the code assumes "pinfo->prefix_len" and ifp->prefix_len are
> equal.
[Dmytro]
Understood.
> > + }
> > + rcu_read_unlock();
> > + if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
> > +
> > + return ifp;
> > +}
> > +
> > int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > const struct prefix_info *pinfo,
> > struct inet6_dev *in6_dev,
> > @@ -2576,9 +2618,16 @@ int addrconf_prefix_rcv_add_addr(struct
> > u32 addr_flags, bool sllao, bool tokenized,
> > __u32 valid_lft, u32 prefered_lft)
> > {
> > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + struct inet6_ifaddr *ifp = NULL;
> > + int plen = pinfo->prefix_len;
> > int create = 0;
> >
> > + if (plen > 0 && plen <= 128 && plen != 64 &&
> > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY)
> > + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> > + else
> > + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > +
> > if (!ifp && valid_lft) {
> > int max_addresses = in6_dev->cnf.max_addresses;
> > struct ifa6_config cfg = {
>
> I am wondering if we should enable this feature by default at this moment
> because the spec is personal internet draft and some test suites might
> consider this feature violates standards.
[Dmytro]
1. By default the /64 plen is send by the router in RA.
plen ==/64 is default behaviour for me.
We are NOT replacing plen == /64 with this patch.
Variable SLAAC is more like an additional functionality.
If and only IF router sends plen !=64 the patch functionality MAY be activated otherwise it is "dormant".
2. After a discussion with my colleague we come up with the next ideas:
- the implementation of IIDs whose length is arbitrary. The RFC7217, as
implemented here optionally, allows for IIDs of any length. The IETF
consensus status of that RFC is on the Standards Track,
and the status is "PROPOSED STANDARD" (the next consensus level that
this RFC could head for is DRAFT STANDARD; preceding levels through
which the document already went successfully: are Individual Draft
submission, WG adoption, Last Call, AUTH48, published).
- the linux kernel supports IPv6 NAT in the mainline - 'masquerading'.
The feature IPv6 NAT is not supported at all by the IETF: the
consensus level is something like complete rejection. Yet it is fully
supported in the kernel.
- the openbsd (not freebsd) implementations already support RFC 7217
IIDs of arbitrary length: send an RA with plen 65 and the receiving
Host will form an IID of length 63 and an IPv6 address. Why linux would
not allow this?
3. Possible solutions:
3.a) enable this feature as additional functionality, only when plen !=64, and keep it "dormant" by default.
3.b) Add sysctl net.ipv6.conf.enp0s3.variable_slaac = 1
3.c) A possibility is that this feature will be present in the make menuconfig.
> > @@ -2657,6 +2706,91 @@ int addrconf_prefix_rcv_add_addr(struct
> > }
> > EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
> >
> > +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > +{
> > + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > + return true;
> > +
> > + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > + return true;
> > +
> > + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > + return true;
> > +
> > + return false;
> > +}
> > +
> > +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> > + u8 dad_count,
> > + const struct inet6_dev *idev,
> > + unsigned int rcvd_prfx_len,
> > + bool stable_privacy_mode)
> > +{
> > + static union {
> > + char __data[SHA1_BLOCK_SIZE];
> > + struct {
> > + struct in6_addr secret;
> > + __be32 prefix[2];
> > + unsigned char hwaddr[MAX_ADDR_LEN];
> > + u8 dad_count;
> > + } __packed;
> > + } data;
> > + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> > + static __u32 digest[SHA1_DIGEST_WORDS];
> > + struct net *net = dev_net(idev->dev);
> > + static DEFINE_SPINLOCK(lock);
> > + struct in6_addr secret;
> > + struct in6_addr temp;
> > +
> > + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> > +
> > + if (stable_privacy_mode) {
> > + if (idev->cnf.stable_secret.initialized)
> > + secret = idev->cnf.stable_secret.secret;
> > + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> > + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> > + else
> > + return -1;
> > + }
> > +
> > +retry:
> > + spin_lock_bh(&lock);
> > + if (stable_privacy_mode) {
> > + sha1_init(digest);
> > + memset(&data, 0, sizeof(data));
> > + memset(workspace, 0, sizeof(workspace));
> > + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> > + data.prefix[0] = address->s6_addr32[0];
> > + data.prefix[1] = address->s6_addr32[1];
> > + data.secret = secret;
> > + data.dad_count = dad_count;
> > +
> > + sha1_transform(digest, data.__data, workspace);
> > +
> > + temp = *address;
> > + temp.s6_addr32[0] = (__force __be32)digest[0];
> > + temp.s6_addr32[1] = (__force __be32)digest[1];
> > + temp.s6_addr32[2] = (__force __be32)digest[2];
> > + temp.s6_addr32[3] = (__force __be32)digest[3];
>
> I do not understand why you copy *address and then overwrite
> by digest?
[Dmytro]
Originally it comes from "ipv6_generate_stable_address()".
it is present there because only 64bits of temp are replaced by digest.
In this case, we replace 128 bits thus I agree: it is misleading. I will fix that.
> > + } else {
> > + temp = *address;
> > + get_random_bytes(temp.s6_addr32, 16);
> > + }
> > + spin_unlock_bh(&lock);
> > +
> > + if (ipv6_reserved_interfaceid(temp)) {
> > + dad_count++;
> > + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> > + return -1;
> > + goto retry;
> > + }
> > + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> > + *address = temp;
> > + return 0;
> > +}
> > +
> > void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> > {
> > struct prefix_info *pinfo;
> > @@ -2781,9 +2915,33 @@ void addrconf_prefix_rcv(struct net_devi
> > dev_addr_generated = true;
> > }
> > goto ok;
> > + } else if (pinfo->prefix_len != 64 &&
> > + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128) {
> > + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> > + * draft-mishra-6man-variable-slaac
> > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > + */
> > + memcpy(&addr, &pinfo->prefix, 16);
> > + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + if (!ipv6_gen_addr_var_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + true)) {
> > + addr_flags |= IFA_F_STABLE_PRIVACY;
> > + goto ok;
> > + }
> > + } else if (!ipv6_gen_addr_var_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + false)) {
> > + goto ok;
> > + }
> > + } else {
> > + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> > + pinfo->prefix_len);
> > }
> > - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> > - pinfo->prefix_len);
> > goto put;
> >
> > ok:
> > @@ -3186,22 +3344,6 @@ void addrconf_add_linklocal(struct inet6
> > }
> > EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
> >
> > -static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > -{
> > - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > - return true;
> > -
> > - if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > - return true;
> > -
> > - if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > - return true;
> > -
> > - return false;
> > -}
> > -
> > static int ipv6_generate_stable_address(struct in6_addr *address,
> > u8 dad_count,
> > const struct inet6_dev *idev)
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V8] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-11-20 9:26 ` [PATCH net-next V7] " Dmytro Shytyi
2020-11-23 13:26 ` Hideaki Yoshifuji
@ 2020-12-09 3:27 ` Dmytro Shytyi
2020-12-16 0:00 ` David Miller
2020-12-16 22:01 ` [PATCH net-next V9] " Dmytro Shytyi
1 sibling, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-12-09 3:27 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel
Variable SLAAC [Can be activated via sysctl]:
SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
Load-Balancer and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index dda61d150a13..67ca3925463c 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -75,6 +75,7 @@ struct ipv6_devconf {
__s32 disable_policy;
__s32 ndisc_tclass;
__s32 rpl_seg_enabled;
+ __s32 variable_slaac;
struct ctl_table_header *sysctl_header;
};
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 13e8751bf24a..f2af4f9fba2d 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -189,7 +189,8 @@ enum {
DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
DEVCONF_NDISC_TCLASS,
DEVCONF_RPL_SEG_ENABLED,
- DEVCONF_MAX
+ DEVCONF_MAX,
+ DEVCONF_VARIABLE_SLAAC
};
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index eff2cacd5209..07afe4ce984e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
.disable_policy = 0,
.rpl_seg_enabled = 0,
+ .variable_slaac = 0,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
.disable_policy = 0,
.rpl_seg_enabled = 0,
+ .variable_slaac = 0,
};
/* Check if link is ready: is it up and is a valid qdisc available */
@@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
+ idev->cnf.variable_slaac) {
+ get_random_bytes(addr.s6_addr, 16);
+ ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2569,6 +2577,37 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}
+static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result_base = NULL;
+ struct inet6_ifaddr *result = NULL;
+ bool prfxs_equal;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ prfxs_equal =
+ ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+
+ return ifp;
+}
+
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
const struct prefix_info *pinfo,
struct inet6_dev *in6_dev,
@@ -2576,9 +2615,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
+ int plen = pinfo->prefix_len;
int create = 0;
+ if (plen > 0 && plen <= 128 && plen != 64 &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+ in6_dev->cnf.variable_slaac)
+ ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
+ else
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2657,6 +2704,90 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
}
EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
+static bool ipv6_reserved_interfaceid(struct in6_addr address)
+{
+ if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0x02005eff) &&
+ ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0xfdffffff) &&
+ ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
+ return true;
+
+ return false;
+}
+
+static int ipv6_gen_addr_var_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ struct net *net = dev_net(idev->dev);
+ static DEFINE_SPINLOCK(lock);
+ struct in6_addr secret;
+ struct in6_addr temp;
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
+ *address = temp;
+ return 0;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2781,9 +2912,34 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
dev_addr_generated = true;
}
goto ok;
+ } else if (pinfo->prefix_len != 64 &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128 &&
+ in6_dev->cnf.variable_slaac) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3186,22 +3342,6 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
}
EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
-static bool ipv6_reserved_interfaceid(struct in6_addr address)
-{
- if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
- return true;
-
- if (address.s6_addr32[2] == htonl(0x02005eff) &&
- ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
- return true;
-
- if (address.s6_addr32[2] == htonl(0xfdffffff) &&
- ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
- return true;
-
- return false;
-}
-
static int ipv6_generate_stable_address(struct in6_addr *address,
u8 dad_count,
const struct inet6_dev *idev)
@@ -5517,6 +5657,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass;
array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled;
+ array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
}
static inline size_t inet6_ifla6_size(void)
@@ -6897,6 +7038,13 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644,
.proc_handler = proc_dointvec,
},
+ {
+ .procname = "variable_slaac",
+ .data = &ipv6_devconf.variable_slaac,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{
/* sentinel */
}
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V8] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-09 3:27 ` [PATCH net-next V8] " Dmytro Shytyi
@ 2020-12-16 0:00 ` David Miller
2020-12-16 14:01 ` Dmytro Shytyi
2020-12-16 22:01 ` [PATCH net-next V9] " Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: David Miller @ 2020-12-16 0:00 UTC (permalink / raw)
To: dmytro; +Cc: kuba, yoshfuji, kuznet, liuhangbin, netdev, linux-kernel
From: Dmytro Shytyi <dmytro@shytyi.net>
Date: Wed, 09 Dec 2020 04:27:54 +0100
> Variable SLAAC [Can be activated via sysctl]:
> SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> Load-Balancer and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> ---
> diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> index dda61d150a13..67ca3925463c 100644
> --- a/include/linux/ipv6.h
> +++ b/include/linux/ipv6.h
> @@ -75,6 +75,7 @@ struct ipv6_devconf {
> __s32 disable_policy;
> __s32 ndisc_tclass;
> __s32 rpl_seg_enabled;
> + __s32 variable_slaac;
>
> struct ctl_table_header *sysctl_header;
> };
> diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> index 13e8751bf24a..f2af4f9fba2d 100644
> --- a/include/uapi/linux/ipv6.h
> +++ b/include/uapi/linux/ipv6.h
> @@ -189,7 +189,8 @@ enum {
> DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> DEVCONF_NDISC_TCLASS,
> DEVCONF_RPL_SEG_ENABLED,
> - DEVCONF_MAX
> + DEVCONF_MAX,
> + DEVCONF_VARIABLE_SLAAC
> };
>
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index eff2cacd5209..07afe4ce984e 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> .disable_policy = 0,
> .rpl_seg_enabled = 0,
> + .variable_slaac = 0,
> };
>
> static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> .disable_policy = 0,
> .rpl_seg_enabled = 0,
> + .variable_slaac = 0,
> };
>
> /* Check if link is ready: is it up and is a valid qdisc available */
> @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> + idev->cnf.variable_slaac) {
> + get_random_bytes(addr.s6_addr, 16);
> + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> + }
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2569,6 +2577,37 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> }
>
> +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result_base = NULL;
> + struct inet6_ifaddr *result = NULL;
> + bool prfxs_equal;
> +
> + result_base = result;
This is NULL, are you sure you didn't mewan to init this to 'ifp'
or similar instead?
Thanks.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V8] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-16 0:00 ` David Miller
@ 2020-12-16 14:01 ` Dmytro Shytyi
2020-12-16 17:28 ` Jakub Kicinski
0 siblings, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2020-12-16 14:01 UTC (permalink / raw)
To: David Miller; +Cc: kuba, yoshfuji, kuznet, liuhangbin, netdev, linux-kernel
Hello David,
Thank you for your comment.
Asnwers in-line.
Take care,
Dmytro SHYTYI
---- On Wed, 16 Dec 2020 01:00:49 +0100 David Miller <davem@davemloft.net> wrote ----
> From: Dmytro Shytyi <dmytro@shytyi.net>
> Date: Wed, 09 Dec 2020 04:27:54 +0100
>
> > Variable SLAAC [Can be activated via sysctl]:
> > SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > Load-Balancer and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > ---
> > diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> > index dda61d150a13..67ca3925463c 100644
> > --- a/include/linux/ipv6.h
> > +++ b/include/linux/ipv6.h
> > @@ -75,6 +75,7 @@ struct ipv6_devconf {
> > __s32 disable_policy;
> > __s32 ndisc_tclass;
> > __s32 rpl_seg_enabled;
> > + __s32 variable_slaac;
> >
> > struct ctl_table_header *sysctl_header;
> > };
> > diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> > index 13e8751bf24a..f2af4f9fba2d 100644
> > --- a/include/uapi/linux/ipv6.h
> > +++ b/include/uapi/linux/ipv6.h
> > @@ -189,7 +189,8 @@ enum {
> > DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> > DEVCONF_NDISC_TCLASS,
> > DEVCONF_RPL_SEG_ENABLED,
> > - DEVCONF_MAX
> > + DEVCONF_MAX,
> > + DEVCONF_VARIABLE_SLAAC
> > };
> >
> >
> > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > index eff2cacd5209..07afe4ce984e 100644
> > --- a/net/ipv6/addrconf.c
> > +++ b/net/ipv6/addrconf.c
> > @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > .disable_policy = 0,
> > .rpl_seg_enabled = 0,
> > + .variable_slaac = 0,
> > };
> >
> > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > .disable_policy = 0,
> > .rpl_seg_enabled = 0,
> > + .variable_slaac = 0,
> > };
> >
> > /* Check if link is ready: is it up and is a valid qdisc available */
> > @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> > goto out;
> > }
> > in6_ifa_hold(ifp);
> > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > - ipv6_gen_rnd_iid(&addr);
> >
> > + if (ifp->prefix_len == 64) {
> > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > + ipv6_gen_rnd_iid(&addr);
> > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> > + idev->cnf.variable_slaac) {
> > + get_random_bytes(addr.s6_addr, 16);
> > + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> > + }
> > age = (now - ifp->tstamp) / HZ;
> >
> > regen_advance = idev->cnf.regen_max_retry *
> > @@ -2569,6 +2577,37 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > }
> >
> > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > + struct inet6_dev *in6_dev,
> > + struct net *net,
> > + const struct prefix_info *pinfo)
> > +{
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct inet6_ifaddr *result = NULL;
> > + bool prfxs_equal;
> > +
> > + result_base = result;
>
> This is NULL, are you sure you didn't mewan to init this to 'ifp'
> or similar instead?
[Dmytro] I put the entire function to comment below the instructions.
[Dmytro]:
+static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result_base = NULL;
+ struct inet6_ifaddr *result = NULL;
+ bool prfxs_equal;
+
+ result_base = result;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ prfxs_equal =
+ ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
+
+ return ifp;
+}
+
[Dmytro]:
1st initial stage is :
+ result_base = result;
2nd stage is (as you mention, 'result' will be assigned to 'ifp', in the process):
+ result = ifp;
3rd stage is to compare if "result_base" and "result" are not equal (and take required action).
if (result_base != result)
+ ifp = result;
+ else
+ ifp = NULL;
Looks more/less ok for me.
Thanks.
> Thanks.
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V8] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-16 14:01 ` Dmytro Shytyi
@ 2020-12-16 17:28 ` Jakub Kicinski
2020-12-16 21:56 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2020-12-16 17:28 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: David Miller, yoshfuji, kuznet, liuhangbin, netdev, linux-kernel
On Wed, 16 Dec 2020 15:01:33 +0100 Dmytro Shytyi wrote:
> Hello David,
>
> Thank you for your comment.
> Asnwers in-line.
>
> Take care,
>
> Dmytro SHYTYI
>
>
> ---- On Wed, 16 Dec 2020 01:00:49 +0100 David Miller <davem@davemloft.net> wrote ----
>
> > From: Dmytro Shytyi <dmytro@shytyi.net>
> > Date: Wed, 09 Dec 2020 04:27:54 +0100
> >
> > > Variable SLAAC [Can be activated via sysctl]:
> > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > generated hostID or stable privacy + privacy extensions).
> > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > > Load-Balancer and /72 to wired connected devices.
> > > IETF document that defines problem statement:
> > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > IETF document that specifies variable slaac:
> > > draft-mishra-6man-variable-slaac
> > >
> > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > > ---
> > > diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> > > index dda61d150a13..67ca3925463c 100644
> > > --- a/include/linux/ipv6.h
> > > +++ b/include/linux/ipv6.h
> > > @@ -75,6 +75,7 @@ struct ipv6_devconf {
> > > __s32 disable_policy;
> > > __s32 ndisc_tclass;
> > > __s32 rpl_seg_enabled;
> > > + __s32 variable_slaac;
> > >
> > > struct ctl_table_header *sysctl_header;
> > > };
> > > diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> > > index 13e8751bf24a..f2af4f9fba2d 100644
> > > --- a/include/uapi/linux/ipv6.h
> > > +++ b/include/uapi/linux/ipv6.h
> > > @@ -189,7 +189,8 @@ enum {
> > > DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> > > DEVCONF_NDISC_TCLASS,
> > > DEVCONF_RPL_SEG_ENABLED,
> > > - DEVCONF_MAX
> > > + DEVCONF_MAX,
> > > + DEVCONF_VARIABLE_SLAAC
> > > };
> > >
> > >
> > > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > > index eff2cacd5209..07afe4ce984e 100644
> > > --- a/net/ipv6/addrconf.c
> > > +++ b/net/ipv6/addrconf.c
> > > @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > .disable_policy = 0,
> > > .rpl_seg_enabled = 0,
> > > + .variable_slaac = 0,
> > > };
> > >
> > > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > .disable_policy = 0,
> > > .rpl_seg_enabled = 0,
> > > + .variable_slaac = 0,
> > > };
> > >
> > > /* Check if link is ready: is it up and is a valid qdisc available */
> > > @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> > > goto out;
> > > }
> > > in6_ifa_hold(ifp);
> > > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > - ipv6_gen_rnd_iid(&addr);
> > >
> > > + if (ifp->prefix_len == 64) {
> > > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > + ipv6_gen_rnd_iid(&addr);
> > > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> > > + idev->cnf.variable_slaac) {
> > > + get_random_bytes(addr.s6_addr, 16);
> > > + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> > > + }
> > > age = (now - ifp->tstamp) / HZ;
> > >
> > > regen_advance = idev->cnf.regen_max_retry *
> > > @@ -2569,6 +2577,37 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> > > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > > }
> > >
> > > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > > + struct inet6_dev *in6_dev,
> > > + struct net *net,
> > > + const struct prefix_info *pinfo)
> > > +{
> > > + struct inet6_ifaddr *result_base = NULL;
> > > + struct inet6_ifaddr *result = NULL;
> > > + bool prfxs_equal;
> > > +
> > > + result_base = result;
> >
> > This is NULL, are you sure you didn't mewan to init this to 'ifp'
> > or similar instead?
>
> [Dmytro] I put the entire function to comment below the instructions.
> [Dmytro]:
> +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result_base = NULL;
> + struct inet6_ifaddr *result = NULL;
> + bool prfxs_equal;
> +
> + result_base = result;
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + prfxs_equal =
> + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> + if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
> +
> + return ifp;
> +}
> +
>
> [Dmytro]:
> 1st initial stage is :
> + result_base = result;
>
> 2nd stage is (as you mention, 'result' will be assigned to 'ifp', in the process):
> + result = ifp;
>
> 3rd stage is to compare if "result_base" and "result" are not equal (and take required action).
> if (result_base != result)
> + ifp = result;
> + else
> + ifp = NULL;
>
> Looks more/less ok for me.
I think I see what you're trying to do here. Use result_base as a
"marker" or the base value?
But I'd say it makes the code harder to follow. It looks like this:
result_base = NULL;
result = NULL;
result_base = result
lock()
for ...
/* search logic */
unlock()
if (result == result_base)
ifp = result
else
ifp = NULL
return NULL
This would be a lot simpler, and functionally equivalent:
result = NULL
lock()
for ...
/* search logic */
unlock()
return result
Right?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V8] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-16 17:28 ` Jakub Kicinski
@ 2020-12-16 21:56 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-12-16 21:56 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David Miller, yoshfuji, kuznet, liuhangbin, netdev, linux-kernel
Hello Jakub,
---- On Wed, 16 Dec 2020 18:28:31 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> On Wed, 16 Dec 2020 15:01:33 +0100 Dmytro Shytyi wrote:
> > Hello David,
> >
> > Thank you for your comment.
> > Asnwers in-line.
> >
> > Take care,
> >
> > Dmytro SHYTYI
> >
> >
> > ---- On Wed, 16 Dec 2020 01:00:49 +0100 David Miller <davem@davemloft.net> wrote ----
> >
> > > From: Dmytro Shytyi <dmytro@shytyi.net>
> > > Date: Wed, 09 Dec 2020 04:27:54 +0100
> > >
> > > > Variable SLAAC [Can be activated via sysctl]:
> > > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > > generated hostID or stable privacy + privacy extensions).
> > > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to VNF-Router, /72 to
> > > > Load-Balancer and /72 to wired connected devices.
> > > > IETF document that defines problem statement:
> > > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > > IETF document that specifies variable slaac:
> > > > draft-mishra-6man-variable-slaac
> > > >
> > > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > > > ---
> > > > diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> > > > index dda61d150a13..67ca3925463c 100644
> > > > --- a/include/linux/ipv6.h
> > > > +++ b/include/linux/ipv6.h
> > > > @@ -75,6 +75,7 @@ struct ipv6_devconf {
> > > > __s32 disable_policy;
> > > > __s32 ndisc_tclass;
> > > > __s32 rpl_seg_enabled;
> > > > + __s32 variable_slaac;
> > > >
> > > > struct ctl_table_header *sysctl_header;
> > > > };
> > > > diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> > > > index 13e8751bf24a..f2af4f9fba2d 100644
> > > > --- a/include/uapi/linux/ipv6.h
> > > > +++ b/include/uapi/linux/ipv6.h
> > > > @@ -189,7 +189,8 @@ enum {
> > > > DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> > > > DEVCONF_NDISC_TCLASS,
> > > > DEVCONF_RPL_SEG_ENABLED,
> > > > - DEVCONF_MAX
> > > > + DEVCONF_MAX,
> > > > + DEVCONF_VARIABLE_SLAAC
> > > > };
> > > >
> > > >
> > > > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > > > index eff2cacd5209..07afe4ce984e 100644
> > > > --- a/net/ipv6/addrconf.c
> > > > +++ b/net/ipv6/addrconf.c
> > > > @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> > > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > > .disable_policy = 0,
> > > > .rpl_seg_enabled = 0,
> > > > + .variable_slaac = 0,
> > > > };
> > > >
> > > > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > > @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > > .disable_policy = 0,
> > > > .rpl_seg_enabled = 0,
> > > > + .variable_slaac = 0,
> > > > };
> > > >
> > > > /* Check if link is ready: is it up and is a valid qdisc available */
> > > > @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> > > > goto out;
> > > > }
> > > > in6_ifa_hold(ifp);
> > > > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > > - ipv6_gen_rnd_iid(&addr);
> > > >
> > > > + if (ifp->prefix_len == 64) {
> > > > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > > + ipv6_gen_rnd_iid(&addr);
> > > > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> > > > + idev->cnf.variable_slaac) {
> > > > + get_random_bytes(addr.s6_addr, 16);
> > > > + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> > > > + }
> > > > age = (now - ifp->tstamp) / HZ;
> > > >
> > > > regen_advance = idev->cnf.regen_max_retry *
> > > > @@ -2569,6 +2577,37 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> > > > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > > > }
> > > >
> > > > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > > > + struct inet6_dev *in6_dev,
> > > > + struct net *net,
> > > > + const struct prefix_info *pinfo)
> > > > +{
> > > > + struct inet6_ifaddr *result_base = NULL;
> > > > + struct inet6_ifaddr *result = NULL;
> > > > + bool prfxs_equal;
> > > > +
> > > > + result_base = result;
> > >
> > > This is NULL, are you sure you didn't mewan to init this to 'ifp'
> > > or similar instead?
> >
> > [Dmytro] I put the entire function to comment below the instructions.
> > [Dmytro]:
> > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > + struct inet6_dev *in6_dev,
> > + struct net *net,
> > + const struct prefix_info *pinfo)
> > +{
> > + struct inet6_ifaddr *result_base = NULL;
> > + struct inet6_ifaddr *result = NULL;
> > + bool prfxs_equal;
> > +
> > + result_base = result;
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > + prfxs_equal =
> > + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
> > + }
> > + rcu_read_unlock();
> > + if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
> > +
> > + return ifp;
> > +}
> > +
> >
> > [Dmytro]:
> > 1st initial stage is :
> > + result_base = result;
> >
> > 2nd stage is (as you mention, 'result' will be assigned to 'ifp', in the process):
> > + result = ifp;
> >
> > 3rd stage is to compare if "result_base" and "result" are not equal (and take required action).
> > if (result_base != result)
> > + ifp = result;
> > + else
> > + ifp = NULL;
> >
> > Looks more/less ok for me.
>
> I think I see what you're trying to do here. Use result_base as a
> "marker" or the base value?
>
> But I'd say it makes the code harder to follow. It looks like this:
>
> result_base = NULL;
> result = NULL;
>
> result_base = result
> lock()
> for ...
> /* search logic */
> unlock()
>
> if (result == result_base)
> ifp = result
> else
> ifp = NULL
> return NULL
>
> This would be a lot simpler, and functionally equivalent:
>
> result = NULL
>
> lock()
> for ...
> /* search logic */
> unlock()
>
> return result
>
> Right?
>
[Dmytro]: I see and I agree. Understood.
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-09 3:27 ` [PATCH net-next V8] " Dmytro Shytyi
2020-12-16 0:00 ` David Miller
@ 2020-12-16 22:01 ` Dmytro Shytyi
2020-12-19 2:03 ` Jakub Kicinski
2021-10-13 23:03 ` [PATCH net-next V10] " Dmytro Shytyi
1 sibling, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2020-12-16 22:01 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel
Variable SLAAC [Can be activated via sysctl]:
SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
SLAAC is required so that downstream interfaces can be further subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
and /72 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index dda61d150a13..67ca3925463c 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -75,6 +75,7 @@ struct ipv6_devconf {
__s32 disable_policy;
__s32 ndisc_tclass;
__s32 rpl_seg_enabled;
+ __s32 variable_slaac;
struct ctl_table_header *sysctl_header;
};
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 13e8751bf24a..f2af4f9fba2d 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -189,7 +189,8 @@ enum {
DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
DEVCONF_NDISC_TCLASS,
DEVCONF_RPL_SEG_ENABLED,
- DEVCONF_MAX
+ DEVCONF_MAX,
+ DEVCONF_VARIABLE_SLAAC
};
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index eff2cacd5209..4afaf2bc8d8b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
.disable_policy = 0,
.rpl_seg_enabled = 0,
+ .variable_slaac = 0,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
.disable_policy = 0,
.rpl_seg_enabled = 0,
+ .variable_slaac = 0,
};
/* Check if link is ready: is it up and is a valid qdisc available */
@@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
+ idev->cnf.variable_slaac) {
+ get_random_bytes(addr.s6_addr, 16);
+ ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2569,6 +2577,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}
+static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result = NULL;
+ bool prfxs_equal;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ prfxs_equal =
+ ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return result;
+}
+
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
const struct prefix_info *pinfo,
struct inet6_dev *in6_dev,
@@ -2576,9 +2609,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
+ int plen = pinfo->prefix_len;
int create = 0;
+ if (plen > 0 && plen <= 128 && plen != 64 &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+ in6_dev->cnf.variable_slaac)
+ ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
+ else
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2657,6 +2698,90 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
}
EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
+static bool ipv6_reserved_interfaceid(struct in6_addr address)
+{
+ if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0x02005eff) &&
+ ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0xfdffffff) &&
+ ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
+ return true;
+
+ return false;
+}
+
+static int ipv6_gen_addr_var_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ static union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ } data;
+ static __u32 workspace[SHA1_WORKSPACE_WORDS];
+ static __u32 digest[SHA1_DIGEST_WORDS];
+ struct net *net = dev_net(idev->dev);
+ static DEFINE_SPINLOCK(lock);
+ struct in6_addr secret;
+ struct in6_addr temp;
+
+ BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ spin_lock_bh(&lock);
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(&data, 0, sizeof(data));
+ memset(workspace, 0, sizeof(workspace));
+ memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data.prefix[0] = address->s6_addr32[0];
+ data.prefix[1] = address->s6_addr32[1];
+ data.secret = secret;
+ data.dad_count = dad_count;
+
+ sha1_transform(digest, data.__data, workspace);
+
+ temp.s6_addr32[0] = (__force __be32)digest[0];
+ temp.s6_addr32[1] = (__force __be32)digest[1];
+ temp.s6_addr32[2] = (__force __be32)digest[2];
+ temp.s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ get_random_bytes(temp.s6_addr32, 16);
+ }
+
+ spin_unlock_bh(&lock);
+
+ if (ipv6_reserved_interfaceid(temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
+ *address = temp;
+ return 0;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2781,9 +2906,34 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
dev_addr_generated = true;
}
goto ok;
+ } else if (pinfo->prefix_len != 64 &&
+ pinfo->prefix_len > 0 && pinfo->prefix_len <= 128 &&
+ in6_dev->cnf.variable_slaac) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -3186,22 +3336,6 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
}
EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
-static bool ipv6_reserved_interfaceid(struct in6_addr address)
-{
- if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
- return true;
-
- if (address.s6_addr32[2] == htonl(0x02005eff) &&
- ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
- return true;
-
- if (address.s6_addr32[2] == htonl(0xfdffffff) &&
- ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
- return true;
-
- return false;
-}
-
static int ipv6_generate_stable_address(struct in6_addr *address,
u8 dad_count,
const struct inet6_dev *idev)
@@ -5517,6 +5651,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass;
array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled;
+ array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
}
static inline size_t inet6_ifla6_size(void)
@@ -6897,6 +7032,13 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644,
.proc_handler = proc_dointvec,
},
+ {
+ .procname = "variable_slaac",
+ .data = &ipv6_devconf.variable_slaac,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{
/* sentinel */
}
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-16 22:01 ` [PATCH net-next V9] " Dmytro Shytyi
@ 2020-12-19 2:03 ` Jakub Kicinski
2020-12-19 2:40 ` Maciej Żenczykowski
2021-07-10 19:24 ` Dmytro Shytyi
2021-10-13 23:03 ` [PATCH net-next V10] " Dmytro Shytyi
1 sibling, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2020-12-19 2:03 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: yoshfuji, liuhangbin, davem, netdev, David Ahern, Joel Scherpelz,
Maciej Żenczykowski
It'd be great if someone more familiar with our IPv6 code could take a
look. Adding some folks to the CC.
On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> Variable SLAAC [Can be activated via sysctl]:
> SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> SLAAC is required so that downstream interfaces can be further subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> and /72 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
The RFC mentions checking a flag in RA, but I don't see that in this
patch, could you explain?
> diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> index 13e8751bf24a..f2af4f9fba2d 100644
> --- a/include/uapi/linux/ipv6.h
> +++ b/include/uapi/linux/ipv6.h
> @@ -189,7 +189,8 @@ enum {
> DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> DEVCONF_NDISC_TCLASS,
> DEVCONF_RPL_SEG_ENABLED,
> - DEVCONF_MAX
> + DEVCONF_MAX,
MAX should be the last field, no? Isn't it used for sizing tables?
> + DEVCONF_VARIABLE_SLAAC
> };
>
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index eff2cacd5209..4afaf2bc8d8b 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> .disable_policy = 0,
> .rpl_seg_enabled = 0,
> + .variable_slaac = 0,
> };
>
> static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> .disable_policy = 0,
> .rpl_seg_enabled = 0,
> + .variable_slaac = 0,
> };
>
> /* Check if link is ready: is it up and is a valid qdisc available */
> @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> + idev->cnf.variable_slaac) {
> + get_random_bytes(addr.s6_addr, 16);
> + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> + }
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2569,6 +2577,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> }
>
> +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result = NULL;
> + bool prfxs_equal;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + prfxs_equal =
> + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> +
> + return result;
> +}
> +
> int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> const struct prefix_info *pinfo,
> struct inet6_dev *in6_dev,
> @@ -2576,9 +2609,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> u32 addr_flags, bool sllao, bool tokenized,
> __u32 valid_lft, u32 prefered_lft)
> {
> - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + struct inet6_ifaddr *ifp = NULL;
> + int plen = pinfo->prefix_len;
> int create = 0;
>
> + if (plen > 0 && plen <= 128 && plen != 64 &&
> + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
> + in6_dev->cnf.variable_slaac)
> + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> + else
> + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> +
> if (!ifp && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> struct ifa6_config cfg = {
> @@ -2657,6 +2698,90 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> }
> EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
>
> +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> +{
> + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> + return true;
> +
> + return false;
> +}
> +
> +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> + u8 dad_count,
> + const struct inet6_dev *idev,
> + unsigned int rcvd_prfx_len,
> + bool stable_privacy_mode)
> +{
> + static union {
> + char __data[SHA1_BLOCK_SIZE];
> + struct {
> + struct in6_addr secret;
> + __be32 prefix[2];
> + unsigned char hwaddr[MAX_ADDR_LEN];
> + u8 dad_count;
> + } __packed;
> + } data;
> + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> + static __u32 digest[SHA1_DIGEST_WORDS];
> + struct net *net = dev_net(idev->dev);
> + static DEFINE_SPINLOCK(lock);
> + struct in6_addr secret;
> + struct in6_addr temp;
> +
> + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> +
> + if (stable_privacy_mode) {
> + if (idev->cnf.stable_secret.initialized)
> + secret = idev->cnf.stable_secret.secret;
> + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> + else
> + return -1;
> + }
> +
> +retry:
> + spin_lock_bh(&lock);
> + if (stable_privacy_mode) {
> + sha1_init(digest);
> + memset(&data, 0, sizeof(data));
> + memset(workspace, 0, sizeof(workspace));
> + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> + data.prefix[0] = address->s6_addr32[0];
> + data.prefix[1] = address->s6_addr32[1];
> + data.secret = secret;
> + data.dad_count = dad_count;
> +
> + sha1_transform(digest, data.__data, workspace);
> +
> + temp.s6_addr32[0] = (__force __be32)digest[0];
> + temp.s6_addr32[1] = (__force __be32)digest[1];
> + temp.s6_addr32[2] = (__force __be32)digest[2];
> + temp.s6_addr32[3] = (__force __be32)digest[3];
> + } else {
> + get_random_bytes(temp.s6_addr32, 16);
> + }
> +
> + spin_unlock_bh(&lock);
Is there a reason this code declares all this state on the stack and
protects it with a lock rather than just allocating the memory with
kmalloc()?
> + if (ipv6_reserved_interfaceid(temp)) {
> + dad_count++;
> + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> + return -1;
> + goto retry;
> + }
> + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> + *address = temp;
> + return 0;
> +}
> +
> void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> {
> struct prefix_info *pinfo;
> @@ -2781,9 +2906,34 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> dev_addr_generated = true;
> }
> goto ok;
> + } else if (pinfo->prefix_len != 64 &&
> + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128 &&
> + in6_dev->cnf.variable_slaac) {
> + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + */
> + memcpy(&addr, &pinfo->prefix, 16);
> + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + true)) {
> + addr_flags |= IFA_F_STABLE_PRIVACY;
> + goto ok;
> + }
> + } else if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + false)) {
> + goto ok;
> + }
> + } else {
> + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> + pinfo->prefix_len);
> }
> - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> - pinfo->prefix_len);
> goto put;
>
> ok:
> @@ -3186,22 +3336,6 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
> }
> EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
>
> -static bool ipv6_reserved_interfaceid(struct in6_addr address)
> -{
> - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> - return true;
> -
> - if (address.s6_addr32[2] == htonl(0x02005eff) &&
> - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> - return true;
> -
> - if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> - return true;
> -
> - return false;
> -}
> -
> static int ipv6_generate_stable_address(struct in6_addr *address,
> u8 dad_count,
> const struct inet6_dev *idev)
> @@ -5517,6 +5651,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
> array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
> array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass;
> array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled;
> + array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
> }
>
> static inline size_t inet6_ifla6_size(void)
> @@ -6897,6 +7032,13 @@ static const struct ctl_table addrconf_sysctl[] = {
> .mode = 0644,
> .proc_handler = proc_dointvec,
> },
> + {
> + .procname = "variable_slaac",
> + .data = &ipv6_devconf.variable_slaac,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec,
> + },
> {
> /* sentinel */
> }
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-19 2:03 ` Jakub Kicinski
@ 2020-12-19 2:40 ` Maciej Żenczykowski
2021-07-12 13:39 ` Dmytro Shytyi
2021-07-10 19:24 ` Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: Maciej Żenczykowski @ 2020-12-19 2:40 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Dmytro Shytyi, yoshfuji, liuhangbin, davem, netdev, David Ahern,
Joel Scherpelz
On Fri, Dec 18, 2020 at 6:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> It'd be great if someone more familiar with our IPv6 code could take a
> look. Adding some folks to the CC.
>
> On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > Variable SLAAC [Can be activated via sysctl]:
> > SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
>
> The RFC mentions checking a flag in RA, but I don't see that in this
> patch, could you explain?
IMHO acceptance of this should *definitely* wait for the RFC to be
accepted/published/standardized (whatever is the right term).
I'm not at all convinced that will happen - this still seems like a
very fresh *draft* of an rfc,
and I'm *sure* it will be argued about.
This sort of functionality will not be particularly useful without
widespread industry
adoption across *all* major operating systems (Windows, Mac/iOS,
Linux/Android, FreeBSD, etc.)
Additionally rollout will take years (due to need for OS updates), so
waiting a few
more months/quarters for the RFC to actually be agreed upon (assuming
it ever is),
will not hurt us.
An implementation that is incompatible with the published RFC will
hurt us more then help us.
Maciej Żenczykowski, Kernel Networking Developer @ Google
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-19 2:03 ` Jakub Kicinski
2020-12-19 2:40 ` Maciej Żenczykowski
@ 2021-07-10 19:24 ` Dmytro Shytyi
2021-07-12 13:23 ` Dmytro Shytyi
1 sibling, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2021-07-10 19:24 UTC (permalink / raw)
To: Jakub Kicinski
Cc: yoshfuji, liuhangbin, davem, netdev, David Ahern, Joel Scherpelz,
"Maciej Żenczykowski"
Hello Jakub,
---- On Sat, 19 Dec 2020 03:03:23 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
> It'd be great if someone more familiar with our IPv6 code could take a
> look. Adding some folks to the CC.
>
> On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > Variable SLAAC [Can be activated via sysctl]:
> > SLAAC with prefixes of arbitrary length in PIO (randomly
> > generated hostID or stable privacy + privacy extensions).
> > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > SLAAC is required so that downstream interfaces can be further subnetted.
> > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > and /72 to wired connected devices.
> > IETF document that defines problem statement:
> > draft-mishra-v6ops-variable-slaac-problem-stmt
> > IETF document that specifies variable slaac:
> > draft-mishra-6man-variable-slaac
> >
> > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
>
> The RFC mentions checking a flag in RA, but I don't see that in this
> patch, could you explain?
[Dmytro]:
Yes, I can. Please check the most recent revision of "draft-mishra-6man-variable-slaac" section 11 ( Variable SLAAC implementation).
You may find in this document in section 11 the next information:
"The linux implementation for Variable SLAAC contains a parameter that
can be controlled in the command line (a sysctl). This parameter has
two potential values: 0 and 1; by default it is set to 0. The value
of 0 means that the stack acts as previously: it does not accept a
prefix of a length other than 64 for the SLAAC process. The valye of
1 makes that prefixes of lengths other than 64 are accepted for the
SLAAC mechanism of forming addresses."
This is done for multiple purposes. One of them is to disable this functionality (VSLAAC) by default.
>
> > diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> > index 13e8751bf24a..f2af4f9fba2d 100644
> > --- a/include/uapi/linux/ipv6.h
> > +++ b/include/uapi/linux/ipv6.h
> > @@ -189,7 +189,8 @@ enum {
> > DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> > DEVCONF_NDISC_TCLASS,
> > DEVCONF_RPL_SEG_ENABLED,
> > - DEVCONF_MAX
> > + DEVCONF_MAX,
>
> MAX should be the last field, no? Isn't it used for sizing tables?
>
> > + DEVCONF_VARIABLE_SLAAC
> > };
> >
> >
> > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > index eff2cacd5209..4afaf2bc8d8b 100644
> > --- a/net/ipv6/addrconf.c
> > +++ b/net/ipv6/addrconf.c
> > @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > .disable_policy = 0,
> > .rpl_seg_enabled = 0,
> > + .variable_slaac = 0,
> > };
> >
> > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > .disable_policy = 0,
> > .rpl_seg_enabled = 0,
> > + .variable_slaac = 0,
> > };
> >
> > /* Check if link is ready: is it up and is a valid qdisc available */
> > @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> > goto out;
> > }
> > in6_ifa_hold(ifp);
> > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > - ipv6_gen_rnd_iid(&addr);
> >
> > + if (ifp->prefix_len == 64) {
> > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > + ipv6_gen_rnd_iid(&addr);
> > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> > + idev->cnf.variable_slaac) {
> > + get_random_bytes(addr.s6_addr, 16);
> > + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> > + }
> > age = (now - ifp->tstamp) / HZ;
> >
> > regen_advance = idev->cnf.regen_max_retry *
> > @@ -2569,6 +2577,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > }
> >
> > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > + struct inet6_dev *in6_dev,
> > + struct net *net,
> > + const struct prefix_info *pinfo)
> > +{
> > + struct inet6_ifaddr *result = NULL;
> > + bool prfxs_equal;
> > +
> > + rcu_read_lock();
> > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > + continue;
> > + prfxs_equal =
> > + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > + result = ifp;
> > + in6_ifa_hold(ifp);
> > + break;
> > + }
> > + }
> > + rcu_read_unlock();
> > +
> > + return result;
> > +}
> > +
> > int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > const struct prefix_info *pinfo,
> > struct inet6_dev *in6_dev,
> > @@ -2576,9 +2609,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > u32 addr_flags, bool sllao, bool tokenized,
> > __u32 valid_lft, u32 prefered_lft)
> > {
> > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > + struct inet6_ifaddr *ifp = NULL;
> > + int plen = pinfo->prefix_len;
> > int create = 0;
> >
> > + if (plen > 0 && plen <= 128 && plen != 64 &&
> > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
> > + in6_dev->cnf.variable_slaac)
> > + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> > + else
> > + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > +
> > if (!ifp && valid_lft) {
> > int max_addresses = in6_dev->cnf.max_addresses;
> > struct ifa6_config cfg = {
> > @@ -2657,6 +2698,90 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > }
> > EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
> >
> > +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > +{
> > + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > + return true;
> > +
> > + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > + return true;
> > +
> > + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > + return true;
> > +
> > + return false;
> > +}
> > +
> > +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> > + u8 dad_count,
> > + const struct inet6_dev *idev,
> > + unsigned int rcvd_prfx_len,
> > + bool stable_privacy_mode)
> > +{
> > + static union {
> > + char __data[SHA1_BLOCK_SIZE];
> > + struct {
> > + struct in6_addr secret;
> > + __be32 prefix[2];
> > + unsigned char hwaddr[MAX_ADDR_LEN];
> > + u8 dad_count;
> > + } __packed;
> > + } data;
> > + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> > + static __u32 digest[SHA1_DIGEST_WORDS];
> > + struct net *net = dev_net(idev->dev);
> > + static DEFINE_SPINLOCK(lock);
> > + struct in6_addr secret;
> > + struct in6_addr temp;
> > +
> > + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> > +
> > + if (stable_privacy_mode) {
> > + if (idev->cnf.stable_secret.initialized)
> > + secret = idev->cnf.stable_secret.secret;
> > + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> > + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> > + else
> > + return -1;
> > + }
> > +
> > +retry:
> > + spin_lock_bh(&lock);
> > + if (stable_privacy_mode) {
> > + sha1_init(digest);
> > + memset(&data, 0, sizeof(data));
> > + memset(workspace, 0, sizeof(workspace));
> > + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> > + data.prefix[0] = address->s6_addr32[0];
> > + data.prefix[1] = address->s6_addr32[1];
> > + data.secret = secret;
> > + data.dad_count = dad_count;
> > +
> > + sha1_transform(digest, data.__data, workspace);
> > +
> > + temp.s6_addr32[0] = (__force __be32)digest[0];
> > + temp.s6_addr32[1] = (__force __be32)digest[1];
> > + temp.s6_addr32[2] = (__force __be32)digest[2];
> > + temp.s6_addr32[3] = (__force __be32)digest[3];
> > + } else {
> > + get_random_bytes(temp.s6_addr32, 16);
> > + }
> > +
> > + spin_unlock_bh(&lock);
>
> Is there a reason this code declares all this state on the stack and
> protects it with a lock rather than just allocating the memory with
> kmalloc()?
>
[Dmytro]:
I assumed that "stable_privacy_mode" is might comming from user context (sysctl net.ipv6.conf.enp0s3.addr_gen_mode=3).
And according to this https://www.kernel.org/doc/htmldocs/kernel-locking/lock-user-bh.html where it is said:
"If a softirq shares data with user context, you have two problems. Firstly, the current user context can be interrupted by a softirq, and secondly, the critical region could be entered from another CPU. This is where spin_lock_bh() (include/linux/spinlock.h) is used. It disables softirqs on that CPU, then grabs the lock."
Thus it might be a place for the spin_lock_bh() and spin_unlock_bh().
> > + if (ipv6_reserved_interfaceid(temp)) {
> > + dad_count++;
> > + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> > + return -1;
> > + goto retry;
> > + }
> > + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> > + *address = temp;
> > + return 0;
> > +}
> > +
> > void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> > {
> > struct prefix_info *pinfo;
> > @@ -2781,9 +2906,34 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> > dev_addr_generated = true;
> > }
> > goto ok;
> > + } else if (pinfo->prefix_len != 64 &&
> > + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128 &&
> > + in6_dev->cnf.variable_slaac) {
> > + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> > + * draft-mishra-6man-variable-slaac
> > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > + */
> > + memcpy(&addr, &pinfo->prefix, 16);
> > + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > + if (!ipv6_gen_addr_var_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + true)) {
> > + addr_flags |= IFA_F_STABLE_PRIVACY;
> > + goto ok;
> > + }
> > + } else if (!ipv6_gen_addr_var_plen(&addr,
> > + 0,
> > + in6_dev,
> > + pinfo->prefix_len,
> > + false)) {
> > + goto ok;
> > + }
> > + } else {
> > + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> > + pinfo->prefix_len);
> > }
> > - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> > - pinfo->prefix_len);
> > goto put;
> >
> > ok:
> > @@ -3186,22 +3336,6 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
> > }
> > EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
> >
> > -static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > -{
> > - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > - return true;
> > -
> > - if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > - return true;
> > -
> > - if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > - return true;
> > -
> > - return false;
> > -}
> > -
> > static int ipv6_generate_stable_address(struct in6_addr *address,
> > u8 dad_count,
> > const struct inet6_dev *idev)
> > @@ -5517,6 +5651,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
> > array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
> > array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass;
> > array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled;
> > + array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
> > }
> >
> > static inline size_t inet6_ifla6_size(void)
> > @@ -6897,6 +7032,13 @@ static const struct ctl_table addrconf_sysctl[] = {
> > .mode = 0644,
> > .proc_handler = proc_dointvec,
> > },
> > + {
> > + .procname = "variable_slaac",
> > + .data = &ipv6_devconf.variable_slaac,
> > + .maxlen = sizeof(int),
> > + .mode = 0644,
> > + .proc_handler = proc_dointvec,
> > + },
> > {
> > /* sentinel */
> > }
>
>
Take care,
Dmytro SHYTYI
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-07-10 19:24 ` Dmytro Shytyi
@ 2021-07-12 13:23 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2021-07-12 13:23 UTC (permalink / raw)
To: Jakub Kicinski
Cc: yoshfuji, liuhangbin, davem, netdev, David Ahern, Joel Scherpelz,
"Maciej Żenczykowski"
Hello Jakub,
---- On Sat, 10 Jul 2021 21:24:46 +0200 Dmytro Shytyi <dmytro@shytyi.net> wrote ----
> Hello Jakub,
>
>
> ---- On Sat, 19 Dec 2020 03:03:23 +0100 Jakub Kicinski <kuba@kernel.org> wrote ----
>
> > It'd be great if someone more familiar with our IPv6 code could take a
> > look. Adding some folks to the CC.
> >
> > On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > > Variable SLAAC [Can be activated via sysctl]:
> > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > generated hostID or stable privacy + privacy extensions).
> > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > > and /72 to wired connected devices.
> > > IETF document that defines problem statement:
> > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > IETF document that specifies variable slaac:
> > > draft-mishra-6man-variable-slaac
> > >
> > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> >
> > The RFC mentions checking a flag in RA, but I don't see that in this
> > patch, could you explain?
> [Dmytro]:
> Yes, I can. Please check the most recent revision of "draft-mishra-6man-variable-slaac" section 11 ( Variable SLAAC implementation).
> You may find in this document in section 11 the next information:
>
> "The linux implementation for Variable SLAAC contains a parameter that
> can be controlled in the command line (a sysctl). This parameter has
> two potential values: 0 and 1; by default it is set to 0. The value
> of 0 means that the stack acts as previously: it does not accept a
> prefix of a length other than 64 for the SLAAC process. The valye of
> 1 makes that prefixes of lengths other than 64 are accepted for the
> SLAAC mechanism of forming addresses."
>
>
> This is done for multiple purposes. One of them is to disable this functionality (VSLAAC) by default.
[Dmytro]:
In other words, the most recent RFC mentions checking sysctl parameter instead of a flag (S-bit) in RA.
> >
> > > diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> > > index 13e8751bf24a..f2af4f9fba2d 100644
> > > --- a/include/uapi/linux/ipv6.h
> > > +++ b/include/uapi/linux/ipv6.h
> > > @@ -189,7 +189,8 @@ enum {
> > > DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
> > > DEVCONF_NDISC_TCLASS,
> > > DEVCONF_RPL_SEG_ENABLED,
> > > - DEVCONF_MAX
> > > + DEVCONF_MAX,
> >
> > MAX should be the last field, no? Isn't it used for sizing tables?
> >
> > > + DEVCONF_VARIABLE_SLAAC
> > > };
> > >
> > >
> > > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > > index eff2cacd5209..4afaf2bc8d8b 100644
> > > --- a/net/ipv6/addrconf.c
> > > +++ b/net/ipv6/addrconf.c
> > > @@ -236,6 +236,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > .disable_policy = 0,
> > > .rpl_seg_enabled = 0,
> > > + .variable_slaac = 0,
> > > };
> > >
> > > static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > @@ -291,6 +292,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> > > .addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64,
> > > .disable_policy = 0,
> > > .rpl_seg_enabled = 0,
> > > + .variable_slaac = 0,
> > > };
> > >
> > > /* Check if link is ready: is it up and is a valid qdisc available */
> > > @@ -1340,9 +1342,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> > > goto out;
> > > }
> > > in6_ifa_hold(ifp);
> > > - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > - ipv6_gen_rnd_iid(&addr);
> > >
> > > + if (ifp->prefix_len == 64) {
> > > + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> > > + ipv6_gen_rnd_iid(&addr);
> > > + } else if (ifp->prefix_len > 0 && ifp->prefix_len <= 128 &&
> > > + idev->cnf.variable_slaac) {
> > > + get_random_bytes(addr.s6_addr, 16);
> > > + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> > > + }
> > > age = (now - ifp->tstamp) / HZ;
> > >
> > > regen_advance = idev->cnf.regen_max_retry *
> > > @@ -2569,6 +2577,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> > > idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> > > }
> > >
> > > +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> > > + struct inet6_dev *in6_dev,
> > > + struct net *net,
> > > + const struct prefix_info *pinfo)
> > > +{
> > > + struct inet6_ifaddr *result = NULL;
> > > + bool prfxs_equal;
> > > +
> > > + rcu_read_lock();
> > > + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> > > + if (!net_eq(dev_net(ifp->idev->dev), net))
> > > + continue;
> > > + prfxs_equal =
> > > + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> > > + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> > > + result = ifp;
> > > + in6_ifa_hold(ifp);
> > > + break;
> > > + }
> > > + }
> > > + rcu_read_unlock();
> > > +
> > > + return result;
> > > +}
> > > +
> > > int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > > const struct prefix_info *pinfo,
> > > struct inet6_dev *in6_dev,
> > > @@ -2576,9 +2609,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > > u32 addr_flags, bool sllao, bool tokenized,
> > > __u32 valid_lft, u32 prefered_lft)
> > > {
> > > - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > > + struct inet6_ifaddr *ifp = NULL;
> > > + int plen = pinfo->prefix_len;
> > > int create = 0;
> > >
> > > + if (plen > 0 && plen <= 128 && plen != 64 &&
> > > + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
> > > + in6_dev->cnf.variable_slaac)
> > > + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> > > + else
> > > + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> > > +
> > > if (!ifp && valid_lft) {
> > > int max_addresses = in6_dev->cnf.max_addresses;
> > > struct ifa6_config cfg = {
> > > @@ -2657,6 +2698,90 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> > > }
> > > EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
> > >
> > > +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > > +{
> > > + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > > + return true;
> > > +
> > > + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > > + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > > + return true;
> > > +
> > > + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > > + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > > + return true;
> > > +
> > > + return false;
> > > +}
> > > +
> > > +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> > > + u8 dad_count,
> > > + const struct inet6_dev *idev,
> > > + unsigned int rcvd_prfx_len,
> > > + bool stable_privacy_mode)
> > > +{
> > > + static union {
> > > + char __data[SHA1_BLOCK_SIZE];
> > > + struct {
> > > + struct in6_addr secret;
> > > + __be32 prefix[2];
> > > + unsigned char hwaddr[MAX_ADDR_LEN];
> > > + u8 dad_count;
> > > + } __packed;
> > > + } data;
> > > + static __u32 workspace[SHA1_WORKSPACE_WORDS];
> > > + static __u32 digest[SHA1_DIGEST_WORDS];
> > > + struct net *net = dev_net(idev->dev);
> > > + static DEFINE_SPINLOCK(lock);
> > > + struct in6_addr secret;
> > > + struct in6_addr temp;
> > > +
> > > + BUILD_BUG_ON(sizeof(data.__data) != sizeof(data));
> > > +
> > > + if (stable_privacy_mode) {
> > > + if (idev->cnf.stable_secret.initialized)
> > > + secret = idev->cnf.stable_secret.secret;
> > > + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> > > + secret = net->ipv6.devconf_dflt->stable_secret.secret;
> > > + else
> > > + return -1;
> > > + }
> > > +
> > > +retry:
> > > + spin_lock_bh(&lock);
> > > + if (stable_privacy_mode) {
> > > + sha1_init(digest);
> > > + memset(&data, 0, sizeof(data));
> > > + memset(workspace, 0, sizeof(workspace));
> > > + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> > > + data.prefix[0] = address->s6_addr32[0];
> > > + data.prefix[1] = address->s6_addr32[1];
> > > + data.secret = secret;
> > > + data.dad_count = dad_count;
> > > +
> > > + sha1_transform(digest, data.__data, workspace);
> > > +
> > > + temp.s6_addr32[0] = (__force __be32)digest[0];
> > > + temp.s6_addr32[1] = (__force __be32)digest[1];
> > > + temp.s6_addr32[2] = (__force __be32)digest[2];
> > > + temp.s6_addr32[3] = (__force __be32)digest[3];
> > > + } else {
> > > + get_random_bytes(temp.s6_addr32, 16);
> > > + }
> > > +
> > > + spin_unlock_bh(&lock);
> >
> > Is there a reason this code declares all this state on the stack and
> > protects it with a lock rather than just allocating the memory with
> > kmalloc()?
> >
> [Dmytro]:
> I assumed that "stable_privacy_mode" is might comming from user context (sysctl net.ipv6.conf.enp0s3.addr_gen_mode=3).
>
> And according to this https://www.kernel.org/doc/htmldocs/kernel-locking/lock-user-bh.html where it is said:
> "If a softirq shares data with user context, you have two problems. Firstly, the current user context can be interrupted by a softirq, and secondly, the critical region could be entered from another CPU. This is where spin_lock_bh() (include/linux/spinlock.h) is used. It disables softirqs on that CPU, then grabs the lock."
>
> Thus it might be a place for the spin_lock_bh() and spin_unlock_bh().
>
>
> > > + if (ipv6_reserved_interfaceid(temp)) {
> > > + dad_count++;
> > > + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> > > + return -1;
> > > + goto retry;
> > > + }
> > > + ipv6_addr_prefix_copy(&temp, address, rcvd_prfx_len);
> > > + *address = temp;
> > > + return 0;
> > > +}
> > > +
> > > void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> > > {
> > > struct prefix_info *pinfo;
> > > @@ -2781,9 +2906,34 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> > > dev_addr_generated = true;
> > > }
> > > goto ok;
> > > + } else if (pinfo->prefix_len != 64 &&
> > > + pinfo->prefix_len > 0 && pinfo->prefix_len <= 128 &&
> > > + in6_dev->cnf.variable_slaac) {
> > > + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> > > + * draft-mishra-6man-variable-slaac
> > > + * draft-mishra-v6ops-variable-slaac-problem-stmt
> > > + */
> > > + memcpy(&addr, &pinfo->prefix, 16);
> > > + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> > > + if (!ipv6_gen_addr_var_plen(&addr,
> > > + 0,
> > > + in6_dev,
> > > + pinfo->prefix_len,
> > > + true)) {
> > > + addr_flags |= IFA_F_STABLE_PRIVACY;
> > > + goto ok;
> > > + }
> > > + } else if (!ipv6_gen_addr_var_plen(&addr,
> > > + 0,
> > > + in6_dev,
> > > + pinfo->prefix_len,
> > > + false)) {
> > > + goto ok;
> > > + }
> > > + } else {
> > > + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> > > + pinfo->prefix_len);
> > > }
> > > - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> > > - pinfo->prefix_len);
> > > goto put;
> > >
> > > ok:
> > > @@ -3186,22 +3336,6 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
> > > }
> > > EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
> > >
> > > -static bool ipv6_reserved_interfaceid(struct in6_addr address)
> > > -{
> > > - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> > > - return true;
> > > -
> > > - if (address.s6_addr32[2] == htonl(0x02005eff) &&
> > > - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> > > - return true;
> > > -
> > > - if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> > > - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> > > - return true;
> > > -
> > > - return false;
> > > -}
> > > -
> > > static int ipv6_generate_stable_address(struct in6_addr *address,
> > > u8 dad_count,
> > > const struct inet6_dev *idev)
> > > @@ -5517,6 +5651,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
> > > array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy;
> > > array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass;
> > > array[DEVCONF_RPL_SEG_ENABLED] = cnf->rpl_seg_enabled;
> > > + array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
> > > }
> > >
> > > static inline size_t inet6_ifla6_size(void)
> > > @@ -6897,6 +7032,13 @@ static const struct ctl_table addrconf_sysctl[] = {
> > > .mode = 0644,
> > > .proc_handler = proc_dointvec,
> > > },
> > > + {
> > > + .procname = "variable_slaac",
> > > + .data = &ipv6_devconf.variable_slaac,
> > > + .maxlen = sizeof(int),
> > > + .mode = 0644,
> > > + .proc_handler = proc_dointvec,
> > > + },
> > > {
> > > /* sentinel */
> > > }
> >
> >
>
> Take care,
> Dmytro SHYTYI
>
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-19 2:40 ` Maciej Żenczykowski
@ 2021-07-12 13:39 ` Dmytro Shytyi
2021-07-12 16:42 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2021-07-12 13:39 UTC (permalink / raw)
To: "Maciej Żenczykowski"
Cc: Jakub Kicinski, yoshfuji, liuhangbin, davem, netdev, David Ahern,
Joel Scherpelz
Hello Maciej,
---- On Sat, 19 Dec 2020 03:40:50 +0100 Maciej Żenczykowski <maze@google.com> wrote ----
> On Fri, Dec 18, 2020 at 6:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > It'd be great if someone more familiar with our IPv6 code could take a
> > look. Adding some folks to the CC.
> >
> > On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > > Variable SLAAC [Can be activated via sysctl]:
> > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > generated hostID or stable privacy + privacy extensions).
> > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > > and /72 to wired connected devices.
> > > IETF document that defines problem statement:
> > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > IETF document that specifies variable slaac:
> > > draft-mishra-6man-variable-slaac
> > >
> > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> >
> IMHO acceptance of this should *definitely* wait for the RFC to be
> accepted/published/standardized (whatever is the right term).
[Dmytro]:
There is an implementation of Variable SLAAC in the OpenBSD Operating System.
> I'm not at all convinced that will happen - this still seems like a
> very fresh *draft* of an rfc,
> and I'm *sure* it will be argued about.
[Dmytro]
By default, VSLAAC is disabled, so there are _*no*_ impact on network behavior by default.
> This sort of functionality will not be particularly useful without
> widespread industry
[Dmytro]:
There are use-cases that can profit from radvd-like software and VSLAAC directly.
> adoption across *all* major operating systems (Windows, Mac/iOS,
> Linux/Android, FreeBSD, etc.)
[Dmytro]:
It should be considered to provide users an _*opportunity*_ to get the required feature.
Solution (as an option) present in linux is better, than _no solution_ in linux.
> An implementation that is incompatible with the published RFC will
> hurt us more then help us.
[Dmytro]:
Compatible implementation follows the recent version of document: https://datatracker.ietf.org/doc/draft-mishra-6man-variable-slaac/ The sysctl usage described in the document is used in the implementation to activate/deactivate VSLAAC. By default it is disabled, so there is _*no*_ impact on network behavior by default.
> Maciej Żenczykowski, Kernel Networking Developer @ Google
>
Take care,
Dmytro.
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-07-12 13:39 ` Dmytro Shytyi
@ 2021-07-12 16:42 ` Dmytro Shytyi
2021-07-12 17:51 ` Erik Kline
0 siblings, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2021-07-12 16:42 UTC (permalink / raw)
To: Jakub Kicinski, "Maciej Żenczykowski", yoshfuji
Cc: liuhangbin, davem, netdev, David Ahern, Joel Scherpelz
Hello Jakub, Maciej, Yoshfuji and others,
After discussion with co-authors about this particular point "Internet Draft/RFC" we think the following:
Indeed RFC status shows large agreement among IETF members. And that is the best indicator of a maturity level.
And that is the best to implement the feature in a stable mainline kernel.
At this time VSLAAC is an individual proposal Internet Draft reflecting the opinion of all authors.
It is not adopted by any IETF working group. At the same time we consider submission to 3GPP.
The features in the kernel have optionally "Y/N/M" and status "EXPERIMENTAL/STABLE".
One possibility could be VSLAAC as "N", "EXPERIMENTAL" on the linux-next branch.
Could you consider this possibility more?
If you doubt VSLAAC introducing non-64 bits IID lengths, then one might wonder whether linux supports IIDs of _arbitrary length_,
as specified in the RFC 7217 with maturity level "Standards Track"?
Best regards,
Dmytro Shytyi et al.
---- On Mon, 12 Jul 2021 15:39:27 +0200 Dmytro Shytyi <dmytro@shytyi.net> wrote ----
> Hello Maciej,
>
>
> ---- On Sat, 19 Dec 2020 03:40:50 +0100 Maciej Żenczykowski <maze@google.com> wrote ----
>
> > On Fri, Dec 18, 2020 at 6:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
> > >
> > > It'd be great if someone more familiar with our IPv6 code could take a
> > > look. Adding some folks to the CC.
> > >
> > > On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > > > Variable SLAAC [Can be activated via sysctl]:
> > > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > > generated hostID or stable privacy + privacy extensions).
> > > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > > > and /72 to wired connected devices.
> > > > IETF document that defines problem statement:
> > > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > > IETF document that specifies variable slaac:
> > > > draft-mishra-6man-variable-slaac
> > > >
> > > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > >
>
> > IMHO acceptance of this should *definitely* wait for the RFC to be
> > accepted/published/standardized (whatever is the right term).
>
> [Dmytro]:
> There is an implementation of Variable SLAAC in the OpenBSD Operating System.
>
> > I'm not at all convinced that will happen - this still seems like a
> > very fresh *draft* of an rfc,
> > and I'm *sure* it will be argued about.
>
> [Dmytro]
> By default, VSLAAC is disabled, so there are _*no*_ impact on network behavior by default.
>
> > This sort of functionality will not be particularly useful without
> > widespread industry
>
> [Dmytro]:
> There are use-cases that can profit from radvd-like software and VSLAAC directly.
>
> > adoption across *all* major operating systems (Windows, Mac/iOS,
> > Linux/Android, FreeBSD, etc.)
>
> [Dmytro]:
> It should be considered to provide users an _*opportunity*_ to get the required feature.
> Solution (as an option) present in linux is better, than _no solution_ in linux.
>
> > An implementation that is incompatible with the published RFC will
> > hurt us more then help us.
>
> [Dmytro]:
> Compatible implementation follows the recent version of document: https://datatracker.ietf.org/doc/draft-mishra-6man-variable-slaac/ The sysctl usage described in the document is used in the implementation to activate/deactivate VSLAAC. By default it is disabled, so there is _*no*_ impact on network behavior by default.
>
> > Maciej Żenczykowski, Kernel Networking Developer @ Google
> >
>
> Take care,
> Dmytro.
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-07-12 16:42 ` Dmytro Shytyi
@ 2021-07-12 17:51 ` Erik Kline
2021-07-13 18:47 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Erik Kline @ 2021-07-12 17:51 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: Jakub Kicinski, Maciej Żenczykowski, yoshfuji, liuhangbin,
davem, netdev, David Ahern, Joel Scherpelz
VSLAAC is indeed quite contentious in the IETF, in large part because
it enables a race to the bottom problem for which there is no solution
in sight.
I don't think this should be accepted. It's not in the same category
of some other Y/N/M things where there are issues of kernel size,
absence of some underlying physical support or not, etc.
On Mon, Jul 12, 2021 at 9:42 AM Dmytro Shytyi <dmytro@shytyi.net> wrote:
>
> Hello Jakub, Maciej, Yoshfuji and others,
>
> After discussion with co-authors about this particular point "Internet Draft/RFC" we think the following:
> Indeed RFC status shows large agreement among IETF members. And that is the best indicator of a maturity level.
> And that is the best to implement the feature in a stable mainline kernel.
>
> At this time VSLAAC is an individual proposal Internet Draft reflecting the opinion of all authors.
> It is not adopted by any IETF working group. At the same time we consider submission to 3GPP.
>
> The features in the kernel have optionally "Y/N/M" and status "EXPERIMENTAL/STABLE".
> One possibility could be VSLAAC as "N", "EXPERIMENTAL" on the linux-next branch.
>
> Could you consider this possibility more?
>
> If you doubt VSLAAC introducing non-64 bits IID lengths, then one might wonder whether linux supports IIDs of _arbitrary length_,
> as specified in the RFC 7217 with maturity level "Standards Track"?
>
> Best regards,
> Dmytro Shytyi et al.
>
> ---- On Mon, 12 Jul 2021 15:39:27 +0200 Dmytro Shytyi <dmytro@shytyi.net> wrote ----
>
> > Hello Maciej,
> >
> >
> > ---- On Sat, 19 Dec 2020 03:40:50 +0100 Maciej Żenczykowski <maze@google.com> wrote ----
> >
> > > On Fri, Dec 18, 2020 at 6:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
> > > >
> > > > It'd be great if someone more familiar with our IPv6 code could take a
> > > > look. Adding some folks to the CC.
> > > >
> > > > On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > > > > Variable SLAAC [Can be activated via sysctl]:
> > > > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > > > generated hostID or stable privacy + privacy extensions).
> > > > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > > > > and /72 to wired connected devices.
> > > > > IETF document that defines problem statement:
> > > > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > > > IETF document that specifies variable slaac:
> > > > > draft-mishra-6man-variable-slaac
> > > > >
> > > > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > > >
> >
> > > IMHO acceptance of this should *definitely* wait for the RFC to be
> > > accepted/published/standardized (whatever is the right term).
> >
> > [Dmytro]:
> > There is an implementation of Variable SLAAC in the OpenBSD Operating System.
> >
> > > I'm not at all convinced that will happen - this still seems like a
> > > very fresh *draft* of an rfc,
> > > and I'm *sure* it will be argued about.
> >
> > [Dmytro]
> > By default, VSLAAC is disabled, so there are _*no*_ impact on network behavior by default.
> >
> > > This sort of functionality will not be particularly useful without
> > > widespread industry
> >
> > [Dmytro]:
> > There are use-cases that can profit from radvd-like software and VSLAAC directly.
> >
> > > adoption across *all* major operating systems (Windows, Mac/iOS,
> > > Linux/Android, FreeBSD, etc.)
> >
> > [Dmytro]:
> > It should be considered to provide users an _*opportunity*_ to get the required feature.
> > Solution (as an option) present in linux is better, than _no solution_ in linux.
> >
> > > An implementation that is incompatible with the published RFC will
> > > hurt us more then help us.
> >
> > [Dmytro]:
> > Compatible implementation follows the recent version of document: https://datatracker.ietf.org/doc/draft-mishra-6man-variable-slaac/ The sysctl usage described in the document is used in the implementation to activate/deactivate VSLAAC. By default it is disabled, so there is _*no*_ impact on network behavior by default.
> >
> > > Maciej Żenczykowski, Kernel Networking Developer @ Google
> > >
> >
> > Take care,
> > Dmytro.
> >
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V9] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-07-12 17:51 ` Erik Kline
@ 2021-07-13 18:47 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2021-07-13 18:47 UTC (permalink / raw)
To: Erik Kline
Cc: Jakub Kicinski, "Maciej Żenczykowski",
yoshfuji, liuhangbin, davem, netdev, David Ahern, Joel Scherpelz
In this case, there is another possibility as well: in order to avoid
opening a race to the bottom condition, the VSLAAC code could be
modified to not permit IIDs of length shorter than 64.
What do you think about this possibility?
________________
Dmytro SHYTYI
---- On Mon, 12 Jul 2021 19:51:19 +0200 Erik Kline <ek@google.com> wrote ----
> VSLAAC is indeed quite contentious in the IETF, in large part because
> it enables a race to the bottom problem for which there is no solution
> in sight.
>
> I don't think this should be accepted. It's not in the same category
> of some other Y/N/M things where there are issues of kernel size,
> absence of some underlying physical support or not, etc.
>
>
> On Mon, Jul 12, 2021 at 9:42 AM Dmytro Shytyi <dmytro@shytyi.net> wrote:
> >
> > Hello Jakub, Maciej, Yoshfuji and others,
> >
> > After discussion with co-authors about this particular point "Internet Draft/RFC" we think the following:
> > Indeed RFC status shows large agreement among IETF members. And that is the best indicator of a maturity level.
> > And that is the best to implement the feature in a stable mainline kernel.
> >
> > At this time VSLAAC is an individual proposal Internet Draft reflecting the opinion of all authors.
> > It is not adopted by any IETF working group. At the same time we consider submission to 3GPP.
> >
> > The features in the kernel have optionally "Y/N/M" and status "EXPERIMENTAL/STABLE".
> > One possibility could be VSLAAC as "N", "EXPERIMENTAL" on the linux-next branch.
> >
> > Could you consider this possibility more?
> >
> > If you doubt VSLAAC introducing non-64 bits IID lengths, then one might wonder whether linux supports IIDs of _arbitrary length_,
> > as specified in the RFC 7217 with maturity level "Standards Track"?
> >
> > Best regards,
> > Dmytro Shytyi et al.
> >
> > ---- On Mon, 12 Jul 2021 15:39:27 +0200 Dmytro Shytyi <dmytro@shytyi.net> wrote ----
> >
> > > Hello Maciej,
> > >
> > >
> > > ---- On Sat, 19 Dec 2020 03:40:50 +0100 Maciej Żenczykowski <maze@google.com> wrote ----
> > >
> > > > On Fri, Dec 18, 2020 at 6:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
> > > > >
> > > > > It'd be great if someone more familiar with our IPv6 code could take a
> > > > > look. Adding some folks to the CC.
> > > > >
> > > > > On Wed, 16 Dec 2020 23:01:29 +0100 Dmytro Shytyi wrote:
> > > > > > Variable SLAAC [Can be activated via sysctl]:
> > > > > > SLAAC with prefixes of arbitrary length in PIO (randomly
> > > > > > generated hostID or stable privacy + privacy extensions).
> > > > > > The main problem is that SLAAC RA or PD allocates a /64 by the Wireless
> > > > > > carrier 4G, 5G to a mobile hotspot, however segmentation of the /64 via
> > > > > > SLAAC is required so that downstream interfaces can be further subnetted.
> > > > > > Example: uCPE device (4G + WI-FI enabled) receives /64 via Wireless, and
> > > > > > assigns /72 to VNF-Firewall, /72 to WIFI, /72 to Load-Balancer
> > > > > > and /72 to wired connected devices.
> > > > > > IETF document that defines problem statement:
> > > > > > draft-mishra-v6ops-variable-slaac-problem-stmt
> > > > > > IETF document that specifies variable slaac:
> > > > > > draft-mishra-6man-variable-slaac
> > > > > >
> > > > > > Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> > > > >
> > >
> > > > IMHO acceptance of this should *definitely* wait for the RFC to be
> > > > accepted/published/standardized (whatever is the right term).
> > >
> > > [Dmytro]:
> > > There is an implementation of Variable SLAAC in the OpenBSD Operating System.
> > >
> > > > I'm not at all convinced that will happen - this still seems like a
> > > > very fresh *draft* of an rfc,
> > > > and I'm *sure* it will be argued about.
> > >
> > > [Dmytro]
> > > By default, VSLAAC is disabled, so there are _*no*_ impact on network behavior by default.
> > >
> > > > This sort of functionality will not be particularly useful without
> > > > widespread industry
> > >
> > > [Dmytro]:
> > > There are use-cases that can profit from radvd-like software and VSLAAC directly.
> > >
> > > > adoption across *all* major operating systems (Windows, Mac/iOS,
> > > > Linux/Android, FreeBSD, etc.)
> > >
> > > [Dmytro]:
> > > It should be considered to provide users an _*opportunity*_ to get the required feature.
> > > Solution (as an option) present in linux is better, than _no solution_ in linux.
> > >
> > > > An implementation that is incompatible with the published RFC will
> > > > hurt us more then help us.
> > >
> > > [Dmytro]:
> > > Compatible implementation follows the recent version of document: https://datatracker.ietf.org/doc/draft-mishra-6man-variable-slaac/ The sysctl usage described in the document is used in the implementation to activate/deactivate VSLAAC. By default it is disabled, so there is _*no*_ impact on network behavior by default.
> > >
> > > > Maciej Żenczykowski, Kernel Networking Developer @ Google
> > > >
> > >
> > > Take care,
> > > Dmytro.
> > >
> >
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH net-next V10] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2020-12-16 22:01 ` [PATCH net-next V9] " Dmytro Shytyi
2020-12-19 2:03 ` Jakub Kicinski
@ 2021-10-13 23:03 ` Dmytro Shytyi
2021-10-13 23:20 ` Dmytro Shytyi
2021-10-14 13:20 ` kernel test robot
1 sibling, 2 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2021-10-13 23:03 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel, ek, Jscherpelz
Variable SLAAC:
[Disabled by default. Can be activated via sysctl]
["Race to the bottom" problem is solved]
SLAAC with prefixes of arbitrary length in PIO (randomly
generated hostID or stable privacy + privacy extensions).
The main problem is that SLAAC RA allocates a /64 by the Wireless
carrier 4G, 5G to a mobile hotspot, however segmentation of shorter net-
work prefix (ex. /48) is required so that downstream interfaces can be further
subnetted.
Example: uCPE device (4G + WI-FI enabled) receives /48 via Wireless, and
assigns /56 to VNF-Firewall, /56 to WIFI, /56 to Load-Balancer
and /56 to wired connected devices.
IETF document that defines problem statement:
draft-mishra-v6ops-variable-slaac-problem-stmt
IETF document that specifies variable slaac:
draft-mishra-6man-variable-slaac
Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
---
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index ef4a69865737..076d99874797 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -79,6 +79,7 @@ struct ipv6_devconf {
__u32 ioam6_id;
__u32 ioam6_id_wide;
__u8 ioam6_enabled;
+ __s32 variable_slaac;
struct ctl_table_header *sysctl_header;
};
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index b243a53fa985..25606c267809 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -193,6 +193,7 @@ enum {
DEVCONF_IOAM6_ENABLED,
DEVCONF_IOAM6_ID,
DEVCONF_IOAM6_ID_WIDE,
+ DEVCONF_VARIABLE_SLAAC,
DEVCONF_MAX
};
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c6a90b7bbb70..34a12d7f4fb8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -241,6 +241,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID,
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
+ .variable_slaac = 0,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -300,6 +301,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.ioam6_enabled = 0,
.ioam6_id = IOAM6_DEFAULT_IF_ID,
.ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
+ .variable_slaac = 0,
};
/* Check if link is ready: is it up and is a valid qdisc available */
@@ -1349,9 +1351,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
goto out;
}
in6_ifa_hold(ifp);
- memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
- ipv6_gen_rnd_iid(&addr);
+ if (ifp->prefix_len == 64) {
+ memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
+ ipv6_gen_rnd_iid(&addr);
+ } else if (ifp->prefix_len > 0 && ifp->prefix_len < 64 &&
+ idev->cnf.variable_slaac) {
+ get_random_bytes(addr.s6_addr, 16);
+ ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
+ }
age = (now - ifp->tstamp) / HZ;
regen_advance = idev->cnf.regen_max_retry *
@@ -2579,6 +2587,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}
+static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
+ struct inet6_dev *in6_dev,
+ struct net *net,
+ const struct prefix_info *pinfo)
+{
+ struct inet6_ifaddr *result = NULL;
+ bool prfxs_equal;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
+ if (!net_eq(dev_net(ifp->idev->dev), net))
+ continue;
+ prfxs_equal =
+ ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
+ if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
+ result = ifp;
+ in6_ifa_hold(ifp);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return result;
+}
+
int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
const struct prefix_info *pinfo,
struct inet6_dev *in6_dev,
@@ -2586,9 +2619,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
u32 addr_flags, bool sllao, bool tokenized,
__u32 valid_lft, u32 prefered_lft)
{
- struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+ struct inet6_ifaddr *ifp = NULL;
+ int plen = pinfo->prefix_len;
int create = 0;
+ if (plen > 0 && plen < 64 &&
+ in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+ in6_dev->cnf.variable_slaac)
+ ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
+ else
+ ifp = ipv6_get_ifaddr(net, addr, dev, 1);
+
if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
struct ifa6_config cfg = {
@@ -2667,6 +2708,94 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
}
EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
+static bool ipv6_reserved_interfaceid(struct in6_addr address)
+{
+ if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0x02005eff) &&
+ ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
+ return true;
+
+ if (address.s6_addr32[2] == htonl(0xfdffffff) &&
+ ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
+ return true;
+
+ return false;
+}
+
+static int ipv6_gen_addr_var_plen(struct in6_addr *address,
+ u8 dad_count,
+ const struct inet6_dev *idev,
+ unsigned int rcvd_prfx_len,
+ bool stable_privacy_mode)
+{
+ union data_union {
+ char __data[SHA1_BLOCK_SIZE];
+ struct {
+ struct in6_addr secret;
+ __be32 prefix[2];
+ unsigned char hwaddr[MAX_ADDR_LEN];
+ u8 dad_count;
+ } __packed;
+ };
+ union data_union *data;
+ struct in6_addr *secret;
+ struct in6_addr *temp;
+ struct net *net;
+ int *workspace;
+ int *digest;
+
+ workspace = kmalloc_array(SHA1_WORKSPACE_WORDS, sizeof(__u32), GFP_KERNEL);
+ digest = kmalloc_array(SHA1_DIGEST_WORDS, sizeof(__u32), GFP_KERNEL);
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ secret = kmalloc(sizeof(*secret), GFP_KERNEL);
+ temp = kmalloc(sizeof(*temp), GFP_KERNEL);
+ net = dev_net(idev->dev);
+
+ BUILD_BUG_ON(sizeof(data->__data) != sizeof(*data));
+
+ if (stable_privacy_mode) {
+ if (idev->cnf.stable_secret.initialized)
+ *secret = idev->cnf.stable_secret.secret;
+ else if (net->ipv6.devconf_dflt->stable_secret.initialized)
+ *secret = net->ipv6.devconf_dflt->stable_secret.secret;
+ else
+ return -1;
+ }
+
+retry:
+ if (stable_privacy_mode) {
+ sha1_init(digest);
+ memset(data, 0, sizeof(*data));
+ memset(workspace, 0, sizeof(*workspace));
+ memcpy(data->hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
+ data->prefix[0] = address->s6_addr32[0];
+ data->prefix[1] = address->s6_addr32[1];
+ data->secret = *secret;
+ data->dad_count = dad_count;
+
+ sha1_transform(digest, data->__data, workspace);
+
+ temp->s6_addr32[0] = (__force __be32)digest[0];
+ temp->s6_addr32[1] = (__force __be32)digest[1];
+ temp->s6_addr32[2] = (__force __be32)digest[2];
+ temp->s6_addr32[3] = (__force __be32)digest[3];
+ } else {
+ get_random_bytes(temp->s6_addr32, 16);
+ }
+
+ if (ipv6_reserved_interfaceid(*temp)) {
+ dad_count++;
+ if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
+ return -1;
+ goto retry;
+ }
+ ipv6_addr_prefix_copy(temp, address, rcvd_prfx_len);
+ *address = *temp;
+ return 0;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2791,9 +2920,33 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
dev_addr_generated = true;
}
goto ok;
+ } else if (pinfo->prefix_len > 0 && pinfo->prefix_len < 64 &&
+ in6_dev->cnf.variable_slaac) {
+ /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
+ * draft-mishra-6man-variable-slaac
+ * draft-mishra-v6ops-variable-slaac-problem-stmt
+ */
+ memcpy(&addr, &pinfo->prefix, 16);
+ if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ true)) {
+ addr_flags |= IFA_F_STABLE_PRIVACY;
+ goto ok;
+ }
+ } else if (!ipv6_gen_addr_var_plen(&addr,
+ 0,
+ in6_dev,
+ pinfo->prefix_len,
+ false)) {
+ goto ok;
+ }
+ } else {
+ net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
+ pinfo->prefix_len);
}
- net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
- pinfo->prefix_len);
goto put;
ok:
@@ -5542,6 +5679,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled;
array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
+ array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
}
static inline size_t inet6_ifla6_size(void)
@@ -6905,6 +7043,13 @@ static const struct ctl_table addrconf_sysctl[] = {
.proc_handler = proc_dointvec,
},
+ {
+ .procname = "variable_slaac",
+ .data = &ipv6_devconf.variable_slaac,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
{
.procname = "seg6_enabled",
.data = &ipv6_devconf.seg6_enabled,
^ permalink raw reply related [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V10] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-10-13 23:03 ` [PATCH net-next V10] " Dmytro Shytyi
@ 2021-10-13 23:20 ` Dmytro Shytyi
2021-10-14 18:26 ` Erik Kline
2021-10-14 13:20 ` kernel test robot
1 sibling, 1 reply; 49+ messages in thread
From: Dmytro Shytyi @ 2021-10-13 23:20 UTC (permalink / raw)
To: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel, ek, Jscherpelz
Hello Jakub, Eric, All,
Jakub,
> +retry:
> + spin_lock_bh(&lock);
> + if (stable_privacy_mode) {
> + sha1_init(digest);
> + memset(&data, 0, sizeof(data));
> + memset(workspace, 0, sizeof(workspace));
> + memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> + data.prefix[0] = address->s6_addr32[0];
> + data.prefix[1] = address->s6_addr32[1];
> + data.secret = secret;
> + data.dad_count = dad_count;
> +
> + sha1_transform(digest, data.__data, workspace);
> +
> + temp.s6_addr32[0] = (__force __be32)digest[0];
> + temp.s6_addr32[1] = (__force __be32)digest[1];
> + temp.s6_addr32[2] = (__force __be32)digest[2];
> + temp.s6_addr32[3] = (__force __be32)digest[3];
> + } else {
> + get_random_bytes(temp.s6_addr32, 16);
> + }
> +
> + spin_unlock_bh(&lock);
>Is there a reason this code declares all this state on the stack and
>protects it with a lock rather than just allocating the memory with
>kmalloc()?
As you proposed earlier, in "PATCH net-next V10" the memory is allocated with kmalloc.
Eric,
This patch solves "Race to the bottom" problem in VSLAAC.
Thank you!
Best Regards,
Dmytro SHYTYI
---- On Thu, 14 Oct 2021 01:03:00 +0200 Dmytro Shytyi <dmytro@shytyi.net> wrote ----
> Variable SLAAC:
> [Disabled by default. Can be activated via sysctl]
> ["Race to the bottom" problem is solved]
> SLAAC with prefixes of arbitrary length in PIO (randomly
> generated hostID or stable privacy + privacy extensions).
> The main problem is that SLAAC RA allocates a /64 by the Wireless
> carrier 4G, 5G to a mobile hotspot, however segmentation of shorter net-
> work prefix (ex. /48) is required so that downstream interfaces can be further
> subnetted.
> Example: uCPE device (4G + WI-FI enabled) receives /48 via Wireless, and
> assigns /56 to VNF-Firewall, /56 to WIFI, /56 to Load-Balancer
> and /56 to wired connected devices.
> IETF document that defines problem statement:
> draft-mishra-v6ops-variable-slaac-problem-stmt
> IETF document that specifies variable slaac:
> draft-mishra-6man-variable-slaac
>
> Signed-off-by: Dmytro Shytyi <dmytro@shytyi.net>
> ---
> diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> index ef4a69865737..076d99874797 100644
> --- a/include/linux/ipv6.h
> +++ b/include/linux/ipv6.h
> @@ -79,6 +79,7 @@ struct ipv6_devconf {
> __u32 ioam6_id;
> __u32 ioam6_id_wide;
> __u8 ioam6_enabled;
> + __s32 variable_slaac;
>
> struct ctl_table_header *sysctl_header;
> };
> diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> index b243a53fa985..25606c267809 100644
> --- a/include/uapi/linux/ipv6.h
> +++ b/include/uapi/linux/ipv6.h
> @@ -193,6 +193,7 @@ enum {
> DEVCONF_IOAM6_ENABLED,
> DEVCONF_IOAM6_ID,
> DEVCONF_IOAM6_ID_WIDE,
> + DEVCONF_VARIABLE_SLAAC,
> DEVCONF_MAX
> };
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index c6a90b7bbb70..34a12d7f4fb8 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -241,6 +241,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
> .ioam6_enabled = 0,
> .ioam6_id = IOAM6_DEFAULT_IF_ID,
> .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
> + .variable_slaac = 0,
> };
>
> static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> @@ -300,6 +301,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> .ioam6_enabled = 0,
> .ioam6_id = IOAM6_DEFAULT_IF_ID,
> .ioam6_id_wide = IOAM6_DEFAULT_IF_ID_WIDE,
> + .variable_slaac = 0,
> };
>
> /* Check if link is ready: is it up and is a valid qdisc available */
> @@ -1349,9 +1351,15 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
> goto out;
> }
> in6_ifa_hold(ifp);
> - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> - ipv6_gen_rnd_iid(&addr);
>
> + if (ifp->prefix_len == 64) {
> + memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
> + ipv6_gen_rnd_iid(&addr);
> + } else if (ifp->prefix_len > 0 && ifp->prefix_len < 64 &&
> + idev->cnf.variable_slaac) {
> + get_random_bytes(addr.s6_addr, 16);
> + ipv6_addr_prefix_copy(&addr, &ifp->addr, ifp->prefix_len);
> + }
> age = (now - ifp->tstamp) / HZ;
>
> regen_advance = idev->cnf.regen_max_retry *
> @@ -2579,6 +2587,31 @@ static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
> idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
> }
>
> +static struct inet6_ifaddr *ipv6_cmp_rcvd_prsnt_prfxs(struct inet6_ifaddr *ifp,
> + struct inet6_dev *in6_dev,
> + struct net *net,
> + const struct prefix_info *pinfo)
> +{
> + struct inet6_ifaddr *result = NULL;
> + bool prfxs_equal;
> +
> + rcu_read_lock();
> + list_for_each_entry_rcu(ifp, &in6_dev->addr_list, if_list) {
> + if (!net_eq(dev_net(ifp->idev->dev), net))
> + continue;
> + prfxs_equal =
> + ipv6_prefix_equal(&pinfo->prefix, &ifp->addr, pinfo->prefix_len);
> + if (prfxs_equal && pinfo->prefix_len == ifp->prefix_len) {
> + result = ifp;
> + in6_ifa_hold(ifp);
> + break;
> + }
> + }
> + rcu_read_unlock();
> +
> + return result;
> +}
> +
> int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> const struct prefix_info *pinfo,
> struct inet6_dev *in6_dev,
> @@ -2586,9 +2619,17 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> u32 addr_flags, bool sllao, bool tokenized,
> __u32 valid_lft, u32 prefered_lft)
> {
> - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> + struct inet6_ifaddr *ifp = NULL;
> + int plen = pinfo->prefix_len;
> int create = 0;
>
> + if (plen > 0 && plen < 64 &&
> + in6_dev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
> + in6_dev->cnf.variable_slaac)
> + ifp = ipv6_cmp_rcvd_prsnt_prfxs(ifp, in6_dev, net, pinfo);
> + else
> + ifp = ipv6_get_ifaddr(net, addr, dev, 1);
> +
> if (!ifp && valid_lft) {
> int max_addresses = in6_dev->cnf.max_addresses;
> struct ifa6_config cfg = {
> @@ -2667,6 +2708,94 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
> }
> EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr);
>
> +static bool ipv6_reserved_interfaceid(struct in6_addr address)
> +{
> + if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0x02005eff) &&
> + ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
> + return true;
> +
> + if (address.s6_addr32[2] == htonl(0xfdffffff) &&
> + ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
> + return true;
> +
> + return false;
> +}
> +
> +static int ipv6_gen_addr_var_plen(struct in6_addr *address,
> + u8 dad_count,
> + const struct inet6_dev *idev,
> + unsigned int rcvd_prfx_len,
> + bool stable_privacy_mode)
> +{
> + union data_union {
> + char __data[SHA1_BLOCK_SIZE];
> + struct {
> + struct in6_addr secret;
> + __be32 prefix[2];
> + unsigned char hwaddr[MAX_ADDR_LEN];
> + u8 dad_count;
> + } __packed;
> + };
> + union data_union *data;
> + struct in6_addr *secret;
> + struct in6_addr *temp;
> + struct net *net;
> + int *workspace;
> + int *digest;
> +
> + workspace = kmalloc_array(SHA1_WORKSPACE_WORDS, sizeof(__u32), GFP_KERNEL);
> + digest = kmalloc_array(SHA1_DIGEST_WORDS, sizeof(__u32), GFP_KERNEL);
> + data = kmalloc(sizeof(*data), GFP_KERNEL);
> + secret = kmalloc(sizeof(*secret), GFP_KERNEL);
> + temp = kmalloc(sizeof(*temp), GFP_KERNEL);
> + net = dev_net(idev->dev);
> +
> + BUILD_BUG_ON(sizeof(data->__data) != sizeof(*data));
> +
> + if (stable_privacy_mode) {
> + if (idev->cnf.stable_secret.initialized)
> + *secret = idev->cnf.stable_secret.secret;
> + else if (net->ipv6.devconf_dflt->stable_secret.initialized)
> + *secret = net->ipv6.devconf_dflt->stable_secret.secret;
> + else
> + return -1;
> + }
> +
> +retry:
> + if (stable_privacy_mode) {
> + sha1_init(digest);
> + memset(data, 0, sizeof(*data));
> + memset(workspace, 0, sizeof(*workspace));
> + memcpy(data->hwaddr, idev->dev->perm_addr, idev->dev->addr_len);
> + data->prefix[0] = address->s6_addr32[0];
> + data->prefix[1] = address->s6_addr32[1];
> + data->secret = *secret;
> + data->dad_count = dad_count;
> +
> + sha1_transform(digest, data->__data, workspace);
> +
> + temp->s6_addr32[0] = (__force __be32)digest[0];
> + temp->s6_addr32[1] = (__force __be32)digest[1];
> + temp->s6_addr32[2] = (__force __be32)digest[2];
> + temp->s6_addr32[3] = (__force __be32)digest[3];
> + } else {
> + get_random_bytes(temp->s6_addr32, 16);
> + }
> +
> + if (ipv6_reserved_interfaceid(*temp)) {
> + dad_count++;
> + if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries)
> + return -1;
> + goto retry;
> + }
> + ipv6_addr_prefix_copy(temp, address, rcvd_prfx_len);
> + *address = *temp;
> + return 0;
> +}
> +
> void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> {
> struct prefix_info *pinfo;
> @@ -2791,9 +2920,33 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
> dev_addr_generated = true;
> }
> goto ok;
> + } else if (pinfo->prefix_len > 0 && pinfo->prefix_len < 64 &&
> + in6_dev->cnf.variable_slaac) {
> + /* SLAAC with prefixes of arbitrary length (Variable SLAAC).
> + * draft-mishra-6man-variable-slaac
> + * draft-mishra-v6ops-variable-slaac-problem-stmt
> + */
> + memcpy(&addr, &pinfo->prefix, 16);
> + if (in6_dev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
> + if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + true)) {
> + addr_flags |= IFA_F_STABLE_PRIVACY;
> + goto ok;
> + }
> + } else if (!ipv6_gen_addr_var_plen(&addr,
> + 0,
> + in6_dev,
> + pinfo->prefix_len,
> + false)) {
> + goto ok;
> + }
> + } else {
> + net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
> + pinfo->prefix_len);
> }
> - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n",
> - pinfo->prefix_len);
> goto put;
>
> ok:
> @@ -5542,6 +5679,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
> array[DEVCONF_IOAM6_ENABLED] = cnf->ioam6_enabled;
> array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
> array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
> + array[DEVCONF_VARIABLE_SLAAC] = cnf->variable_slaac;
> }
>
> static inline size_t inet6_ifla6_size(void)
> @@ -6905,6 +7043,13 @@ static const struct ctl_table addrconf_sysctl[] = {
> .proc_handler = proc_dointvec,
>
> },
> + {
> + .procname = "variable_slaac",
> + .data = &ipv6_devconf.variable_slaac,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec,
> + },
> {
> .procname = "seg6_enabled",
> .data = &ipv6_devconf.seg6_enabled,
>
>
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V10] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-10-13 23:03 ` [PATCH net-next V10] " Dmytro Shytyi
2021-10-13 23:20 ` Dmytro Shytyi
@ 2021-10-14 13:20 ` kernel test robot
1 sibling, 0 replies; 49+ messages in thread
From: kernel test robot @ 2021-10-14 13:20 UTC (permalink / raw)
To: Dmytro Shytyi, Jakub Kicinski, yoshfuji, kuznet, liuhangbin,
davem, netdev, linux-kernel, ek, Jscherpelz
Cc: llvm, kbuild-all
[-- Attachment #1: Type: text/plain, Size: 3278 bytes --]
Hi Dmytro,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Dmytro-Shytyi/net-Variable-SLAAC-SLAAC-with-prefixes-of-arbitrary-length-in-PIO/20211014-072015
base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 39e222bfd7f37e7a98069869375b903d7096c113
config: x86_64-randconfig-r013-20211014 (attached as .config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 6c76d0101193aa4eb891a6954ff047eda2f9cf71)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/780991c4b4a62473ddc2bd73ea399061a1c41afd
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Dmytro-Shytyi/net-Variable-SLAAC-SLAAC-with-prefixes-of-arbitrary-length-in-PIO/20211014-072015
git checkout 780991c4b4a62473ddc2bd73ea399061a1c41afd
# save the attached .config to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
>> net/ipv6/addrconf.c:3355:13: error: redefinition of 'ipv6_reserved_interfaceid'
static bool ipv6_reserved_interfaceid(struct in6_addr address)
^
net/ipv6/addrconf.c:2711:13: note: previous definition is here
static bool ipv6_reserved_interfaceid(struct in6_addr address)
^
1 error generated.
vim +/ipv6_reserved_interfaceid +3355 net/ipv6/addrconf.c
^1da177e4c3f41 Linus Torvalds 2005-04-16 3354
622c81d57b392c Hannes Frederic Sowa 2015-03-23 @3355 static bool ipv6_reserved_interfaceid(struct in6_addr address)
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3356 {
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3357 if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0)
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3358 return true;
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3359
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3360 if (address.s6_addr32[2] == htonl(0x02005eff) &&
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3361 ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000)))
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3362 return true;
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3363
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3364 if (address.s6_addr32[2] == htonl(0xfdffffff) &&
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3365 ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80)))
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3366 return true;
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3367
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3368 return false;
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3369 }
622c81d57b392c Hannes Frederic Sowa 2015-03-23 3370
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 31559 bytes --]
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V10] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-10-13 23:20 ` Dmytro Shytyi
@ 2021-10-14 18:26 ` Erik Kline
2021-10-14 21:36 ` Dmytro Shytyi
0 siblings, 1 reply; 49+ messages in thread
From: Erik Kline @ 2021-10-14 18:26 UTC (permalink / raw)
To: Dmytro Shytyi
Cc: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel, Jscherpelz
> This patch solves "Race to the bottom" problem in VSLAAC.
How exactly does this "solve" the fundamental problem?
^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH net-next V10] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO
2021-10-14 18:26 ` Erik Kline
@ 2021-10-14 21:36 ` Dmytro Shytyi
0 siblings, 0 replies; 49+ messages in thread
From: Dmytro Shytyi @ 2021-10-14 21:36 UTC (permalink / raw)
To: Erik Kline
Cc: Jakub Kicinski, yoshfuji, kuznet, liuhangbin, davem, netdev,
linux-kernel, Jscherpelz
> > This patch solves "Race to the bottom" problem in VSLAAC.
>
> How exactly does this "solve" the fundamental problem?
>
VSLAAC is replaced by the SLAAC starting from /64
if (pinfo->prefix_len == 64) {
64_bit_addr_gen
} else if (pinfo->prefix_len > 0 && pinfo->prefix_len < 64 &&
in6_dev->cnf.variable_slaac) {
variable_bit_addr_gen
} else {
net_dbg_ratelimited("IPv6: Prefix with unexpected length %d\n",
pinfo->prefix_len);
}
I meant to say that this is no longer an issue in VSLAAC particular context, considering /128 bits the "bottom".
In this version of the patch, we are not reaching the /128 bit "bottom".
Best regards,
Dmytro SHYTYI.
^ permalink raw reply [flat|nested] 49+ messages in thread
end of thread, other threads:[~2021-10-14 21:37 UTC | newest]
Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <175b25d0c79.f8ce5734515834.1635475016968827598@shytyi.net>
2020-11-10 17:45 ` [PATCH net-next] net: Variable SLAAC: SLAAC with prefixes of arbitrary length in PIO Dmytro Shytyi
2020-11-11 1:34 ` kernel test robot
2020-11-11 20:37 ` [PATCH net-next V2] " Dmytro Shytyi
2020-11-12 15:44 ` [PATCH net-next V3] " Dmytro Shytyi
2020-11-12 16:55 ` Hideaki Yoshifuji
2020-11-13 1:50 ` Dmytro Shytyi
2020-11-13 0:21 ` Jakub Kicinski
2020-11-13 1:50 ` Dmytro Shytyi
2020-11-13 1:56 ` [PATCH net-next V4] " Dmytro Shytyi
2020-11-13 12:38 ` Hideaki Yoshifuji
2020-11-13 19:09 ` Dmytro Shytyi
2020-11-13 19:36 ` [PATCH net-next V5] " Dmytro Shytyi
2020-11-17 20:43 ` Jakub Kicinski
2020-11-18 13:41 ` Dmytro Shytyi
2020-11-18 15:50 ` Jakub Kicinski
2020-11-18 15:56 ` Dmytro Shytyi
2020-11-19 13:37 ` [PATCH net-next V6] " Dmytro Shytyi
2020-11-19 18:44 ` Jakub Kicinski
2020-11-19 19:31 ` Dmytro Shytyi
2020-11-20 1:20 ` Jakub Kicinski
2020-11-20 9:26 ` [PATCH net-next V7] " Dmytro Shytyi
2020-11-23 13:26 ` Hideaki Yoshifuji
2020-11-27 16:54 ` Dmytro Shytyi
2020-12-09 3:27 ` [PATCH net-next V8] " Dmytro Shytyi
2020-12-16 0:00 ` David Miller
2020-12-16 14:01 ` Dmytro Shytyi
2020-12-16 17:28 ` Jakub Kicinski
2020-12-16 21:56 ` Dmytro Shytyi
2020-12-16 22:01 ` [PATCH net-next V9] " Dmytro Shytyi
2020-12-19 2:03 ` Jakub Kicinski
2020-12-19 2:40 ` Maciej Żenczykowski
2021-07-12 13:39 ` Dmytro Shytyi
2021-07-12 16:42 ` Dmytro Shytyi
2021-07-12 17:51 ` Erik Kline
2021-07-13 18:47 ` Dmytro Shytyi
2021-07-10 19:24 ` Dmytro Shytyi
2021-07-12 13:23 ` Dmytro Shytyi
2021-10-13 23:03 ` [PATCH net-next V10] " Dmytro Shytyi
2021-10-13 23:20 ` Dmytro Shytyi
2021-10-14 18:26 ` Erik Kline
2021-10-14 21:36 ` Dmytro Shytyi
2021-10-14 13:20 ` kernel test robot
2020-11-13 0:24 ` [PATCH net-next] " Jakub Kicinski
2020-11-13 0:32 ` [kbuild-all] " Li, Philip
2020-11-13 0:51 ` Jakub Kicinski
2020-11-13 1:01 ` Li, Philip
2020-11-13 1:43 ` Dave Hansen
2020-11-13 1:53 ` Jakub Kicinski
2020-11-13 2:01 ` Dave Hansen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).