* 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 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-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 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
* [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 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: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
* 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
* [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: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
* 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] 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] 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
* 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
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).