Message ID | 20211116060959.32746-1-rocco.yue@mediatek.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net-next,v2] ipv6: don't generate link-local addr in random or privacy mode | expand |
On 11/15/21 11:09 PM, Rocco Yue wrote: > In the 3GPP TS 29.061, here is a description as follows: > "In order to avoid any conflict between the link-local address > of the MS and that of the GGSN, the Interface-Identifier used by > the MS to build its link-local address shall be assigned by the > GGSN. The GGSN ensures the uniqueness of this Interface-Identifier. > The MT shall then enforce the use of this Interface-Identifier by > the TE" > > In other words, in the cellular network, GGSN determines whether > to reply a solicited RA message by identifying the bottom 64 bits > of the source address of the received RS message. Therefore, > cellular network device's ipv6 link-local address should be set > as the format of fe80::(GGSN assigned IID). > > To meet the above spec requirement, this patch adds two new > addr_gen_mode: > > 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable > for cellular networks that support RFC7217. In this mode, the > kernel doesn't generate a link-local address for the cellular > NIC, and generates an ipv6 stable privacy global address after > receiving the RA message. > > 2) IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, in this mode, the kernel > doesn't generate a link-local address for the cellular NIC, > and will use the bottom 64 bits of the link-local address(same > as the IID assigned by GGSN) to form an ipv6 global address > after receiveing the RA message. > > Signed-off-by: Rocco Yue <rocco.yue@mediatek.com> > --- > v1->v2: Add new addr_gen_mode instead of adding a separate sysctl. > > v1 link: > https://patchwork.kernel.org/patch/12353465 > > --- > include/uapi/linux/if_link.h | 2 ++ > net/ipv6/addrconf.c | 22 ++++++++++++++++------ > tools/include/uapi/linux/if_link.h | 2 ++ > 3 files changed, 20 insertions(+), 6 deletions(-) > Reviewed-by: David Ahern <dsahern@kernel.org> you should add tests under tools/testing/selftests/net.
On Tue, 16 Nov 2021 13:21:12 -0700 David Ahern wrote: > Reviewed-by: David Ahern <dsahern@kernel.org> > > you should add tests under tools/testing/selftests/net. Please keep David's review tag and repost with a selftest.
On Tue, Nov 16, 2021 at 3:15 PM Rocco Yue <rocco.yue@mediatek.com> wrote: > > In the 3GPP TS 29.061, here is a description as follows: > "In order to avoid any conflict between the link-local address > of the MS and that of the GGSN, the Interface-Identifier used by > the MS to build its link-local address shall be assigned by the > GGSN. > [...] > 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable > for cellular networks that support RFC7217. In this mode, the > kernel doesn't generate a link-local address for the cellular > NIC, and generates an ipv6 stable privacy global address after > receiving the RA message. It sounds like this would violate RFC 4291 section 2.1 which says "All interfaces are required to have at least one Link-Local unicast address. It is also not what 3GPP requires. 3GPP *does* require a link-local address. It just requires that that the bottom 64 bits of that link-local address be assigned by the network, not randomly. Given that the kernel already supports tokenized interface addresses, a better option here would be to add new addrgen modes where the link-local address is formed from the interface token (idev->token), and the other addresses are formed randomly or via RFC7217. These modes could be called IN6_ADDR_GEN_MODE_RANDOM_LL_TOKEN and IN6_ADDR_GEN_MODE_STABLE_PRIVACY_LL_TOKEN. When setting up the interface, userspace could set disable_ipv6 to 1, then set the interface token and the address generation mode via RTM_SETLINK, then set disable_ipv6 to 0 to start autoconf. The kernel would then form the link-local address via the token (which comes from the network), and then set the global addresses either randomly or via RFC 7217.
On Wed, 2021-11-17 at 13:09 +0800, Lorenzo Colitti wrote: > On Tue, Nov 16, 2021 at 3:15 PM Rocco Yue <rocco.yue@mediatek.com> > wrote: >> >> In the 3GPP TS 29.061, here is a description as follows: >> "In order to avoid any conflict between the link-local address >> of the MS and that of the GGSN, the Interface-Identifier used by >> the MS to build its link-local address shall be assigned by the >> GGSN. >> [...] >> 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable >> for cellular networks that support RFC7217. In this mode, the >> kernel doesn't generate a link-local address for the cellular >> NIC, and generates an ipv6 stable privacy global address after >> receiving the RA message. > > > It sounds like this would violate RFC 4291 section 2.1 which says > "All > interfaces are required to have at least one Link-Local unicast > address. It is also not what 3GPP requires. 3GPP *does* require a > link-local address. It just requires that that the bottom 64 bits of > that link-local address be assigned by the network, not randomly. > Hi Lorenzo, Thanks for your reply. :-) Disabling the kernel's automatic link-local address generation doesn't mean that it violates RFC 4291, because an appropriate link-local addr can be added to the cellulal NIC through ioctl. In fact, the current kernel has similar precedents. For example, when device type is ARPHRD_NONE, and its addr_gen_mode is NONE, the kernel will never generate a link-local addr for such interface. > Given that the kernel already supports tokenized interface addresses, > a better option here would be to add new addrgen modes where the > link-local address is formed from the interface token (idev->token), > and the other addresses are formed randomly or via RFC7217. These > modes could be called IN6_ADDR_GEN_MODE_RANDOM_LL_TOKEN and > IN6_ADDR_GEN_MODE_STABLE_PRIVACY_LL_TOKEN. When setting up the > interface, userspace could set disable_ipv6 to 1, then set the > interface token and the address generation mode via RTM_SETLINK, then > set disable_ipv6 to 0 to start autoconf. The kernel would then form > the link-local address via the token (which comes from the network), > and then set the global addresses either randomly or via RFC 7217. The method you mentioned can also solve the current problem, but it seems to introduce more logic: (1) set the cellular interface addr_gen_mode to RANDOM_LL_TOKEN or PRIVACY_LL_TOKEN; (2) set the cellular interface up; (3) disable ipv6 first; (4) set token addr through netlink; (5) autoconf through the kernel; (6) kernel trigger send RS message; For the current patch, it is simpler, the configure process as follows: (1) set the cellular NIC addr_gen_mode to RANDOM_NO_LLA or PRIVACY_NO_LLA; (2) set the cellular interface up; (3) configure the link-local addr for the NIC by ioctl; (4) kernel trigger send RS message; I wonder to hear what you and David think. Thanks, Rocco
On Wed, Nov 17, 2021 at 4:22 PM Rocco Yue <rocco.yue@mediatek.com> wrote: > Disabling the kernel's automatic link-local address generation > doesn't mean that it violates RFC 4291, because an appropriate > link-local addr can be added to the cellulal NIC through ioctl. Well, it would mean that the kernel requires additional work from userspace to respect the RFC. > The method you mentioned can also solve the current problem, but it > seems to introduce more logic: > (1) set the cellular interface addr_gen_mode to RANDOM_LL_TOKEN or PRIVACY_LL_TOKEN; > (2) set the cellular interface up; > (3) disable ipv6 first; I don't think you need to set the interface up to disable IPv6. Also I think that if the interface is down autoconf won't run so you don't actually need to do this. > (4) set token addr through netlink; Can't 4 be the same as 3? The same netlink message can configure both the addr_gen_mode and the token, no? It seems to me that the following should work, and would be much simpler. 1. Bring the interface down. All addresses are deleted. 2. Send a netlink request to set addr_gen_mode RANDOM_LL_TOKEN or PRIVACY_LL_TOKEN and set the token. 3. Bring the interface up. Autoconf runs. The link-local address is generated from the token. An RS is sent. When the RA is received, the global address is generated using RFC 7217 or randomly. Cheers, Lorenzo
> Can't 4 be the same as 3? The same netlink message can configure both > the addr_gen_mode and the token, no? > > It seems to me that the following should work, and would be much simpler. > > 1. Bring the interface down. All addresses are deleted. > 2. Send a netlink request to set addr_gen_mode RANDOM_LL_TOKEN or > PRIVACY_LL_TOKEN and set the token. > 3. Bring the interface up. Autoconf runs. The link-local address is > generated from the token. An RS is sent. When the RA is received, the > global address is generated using RFC 7217 or randomly. Could you simply manually add an ipv6 link local address to the interface while it is down (ip -6 addr add fe80::..../64 dev X), then bring the interface up (ip link set dev X up)... All that would need to happen is the automatic link local generation would need to be suppressed if there's already a link local ip configured - which sounds like a good idea anyway, since why have two? (btw. even a manually added link local ip will get deleted when the interface gets brought back down)
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index eebd3894fe89..9c5695744c7d 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -428,6 +428,8 @@ enum in6_addr_gen_mode { IN6_ADDR_GEN_MODE_NONE, IN6_ADDR_GEN_MODE_STABLE_PRIVACY, IN6_ADDR_GEN_MODE_RANDOM, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, + IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, }; /* Bridge section */ diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3445f8017430..0045de10f4b5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -392,7 +392,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) timer_setup(&ndev->rs_timer, addrconf_rs_timer, 0); memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); - if (ndev->cnf.stable_secret.initialized) + if (ndev->cnf.stable_secret.initialized && + ndev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA) ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; ndev->cnf.mtu6 = dev->mtu; @@ -2578,7 +2579,8 @@ static void manage_tempaddrs(struct inet6_dev *idev, static bool is_addr_mode_generate_stable(struct inet6_dev *idev) { return idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY || - idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM; + idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM || + idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA; } int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, @@ -3331,6 +3333,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) 0, 0, GFP_KERNEL); break; case IN6_ADDR_GEN_MODE_NONE: + case IN6_ADDR_GEN_MODE_RANDOM_NO_LLA: + case IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA: default: /* will not add any link local address */ break; @@ -5798,7 +5802,9 @@ static int check_addr_gen_mode(int mode) if (mode != IN6_ADDR_GEN_MODE_EUI64 && mode != IN6_ADDR_GEN_MODE_NONE && mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY && - mode != IN6_ADDR_GEN_MODE_RANDOM) + mode != IN6_ADDR_GEN_MODE_RANDOM && + mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA && + mode != IN6_ADDR_GEN_MODE_RANDOM_NO_LLA) return -EINVAL; return 1; } @@ -6428,15 +6434,19 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write, for_each_netdev(net, dev) { struct inet6_dev *idev = __in6_dev_get(dev); - if (idev) { + if (idev && idev->cnf.addr_gen_mode != + IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA) { idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; } } } else { struct inet6_dev *idev = ctl->extra1; - - idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + if (idev->cnf.addr_gen_mode != + IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA) { + idev->cnf.addr_gen_mode = + IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + } } out: diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index b3610fdd1fee..fb69137aea89 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -241,6 +241,8 @@ enum in6_addr_gen_mode { IN6_ADDR_GEN_MODE_NONE, IN6_ADDR_GEN_MODE_STABLE_PRIVACY, IN6_ADDR_GEN_MODE_RANDOM, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, + IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, }; /* Bridge section */
In the 3GPP TS 29.061, here is a description as follows: "In order to avoid any conflict between the link-local address of the MS and that of the GGSN, the Interface-Identifier used by the MS to build its link-local address shall be assigned by the GGSN. The GGSN ensures the uniqueness of this Interface-Identifier. The MT shall then enforce the use of this Interface-Identifier by the TE" In other words, in the cellular network, GGSN determines whether to reply a solicited RA message by identifying the bottom 64 bits of the source address of the received RS message. Therefore, cellular network device's ipv6 link-local address should be set as the format of fe80::(GGSN assigned IID). To meet the above spec requirement, this patch adds two new addr_gen_mode: 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable for cellular networks that support RFC7217. In this mode, the kernel doesn't generate a link-local address for the cellular NIC, and generates an ipv6 stable privacy global address after receiving the RA message. 2) IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, in this mode, the kernel doesn't generate a link-local address for the cellular NIC, and will use the bottom 64 bits of the link-local address(same as the IID assigned by GGSN) to form an ipv6 global address after receiveing the RA message. Signed-off-by: Rocco Yue <rocco.yue@mediatek.com> --- v1->v2: Add new addr_gen_mode instead of adding a separate sysctl. v1 link: https://patchwork.kernel.org/patch/12353465 --- include/uapi/linux/if_link.h | 2 ++ net/ipv6/addrconf.c | 22 ++++++++++++++++------ tools/include/uapi/linux/if_link.h | 2 ++ 3 files changed, 20 insertions(+), 6 deletions(-)