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 <[email protected]>
---
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(-)
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 */
--
2.18.0
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 <[email protected]>
> ---
> 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 <[email protected]>
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 <[email protected]>
>
> 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 <[email protected]> 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 <[email protected]>
> 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 <[email protected]> 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)