[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <175c3036e56.c134a30a177674.8041366564060302157@shytyi.net>
Date: Fri, 13 Nov 2020 20:09:43 +0100
From: Dmytro Shytyi <dmytro@...tyi.net>
To: "Hideaki Yoshifuji" <hideaki.yoshifuji@...aclelinux.com>
Cc: "kuba" <kuba@...nel.org>, "kuznet" <kuznet@....inr.ac.ru>,
"yoshfuji" <yoshfuji@...ux-ipv6.org>,
"liuhangbin" <liuhangbin@...il.com>, "davem" <davem@...emloft.net>,
"netdev" <netdev@...r.kernel.org>,
"linux-kernel" <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH net-next V4] net: Variable SLAAC: SLAAC with prefixes of
arbitrary length in PIO
Hello,
---- On Fri, 13 Nov 2020 13:38:02 +0100 Hideaki Yoshifuji <hideaki.yoshifuji@...aclelinux.com> wrote ----
> Hi,
>
> 2020年11月13日(金) 10:57 Dmytro Shytyi <dmytro@...tyi.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@...tyi.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...
Powered by blists - more mailing lists