* [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses
@ 2026-07-20 18:16 Tim Wong
2026-07-20 18:21 ` [PATCH net-next 2/2] selftests: net: add test for IPv4 address scope ordering Tim Wong
2026-07-21 9:01 ` [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Ido Schimmel
0 siblings, 2 replies; 3+ messages in thread
From: Tim Wong @ 2026-07-20 18:16 UTC (permalink / raw)
To: netdev; +Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
linux-kernel
__inet_insert_ifa() inserts a new primary address by advancing an
insertion pointer past every existing primary address whose scope
is >= the new address's scope. Because IPv4 scope values are
numerically smaller for wider scopes (RT_SCOPE_UNIVERSE < ... <
RT_SCOPE_LINK < RT_SCOPE_HOST), the comparison
ifa->ifa_scope <= ifa1->ifa_scope
is true for a global-scope new address against essentially every
existing entry, so the new address is pushed all the way to the
tail of the primary address list, ending up *after* any link-scope
addresses that were configured earlier.
On an interface carrying a mix of global- and link-scope IPv4
addresses (e.g. a routable address alongside an RFC 3927
169.254.0.0/16 address, or any address explicitly assigned link
scope), this makes the resulting order in in_dev->ifa_list -- and
therefore the order addresses are reported via netlink
(RTM_GETADDR), ioctl (SIOCGIFCONF), and /proc/net -- depend on
configuration order rather than scope. Userspace consumers that
pick the first address returned for an interface (e.g. via
getifaddrs()) can end up preferring a link-scope address over a
global one.
IPv6 already avoids this: ipv6_add_addr() keeps idev->addr_list
ordered so global-scope addresses precede link-local ones
regardless of configuration order.
Fix the comparison so the insertion pointer only advances past
addresses that are at least as global as the new one:
ifa->ifa_scope >= ifa1->ifa_scope
This groups global-scope primary addresses ahead of link-scope
primary addresses in in_dev->ifa_list, preserving insertion order
within each scope group, and brings IPv4 address enumeration order
in line with existing IPv6 behavior.
Signed-off-by: kanman.wong <kanman.wong@dish.com>
---
net/ipv4/devinet.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a35b72662e43..056f2169c6a3 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -510,7 +510,7 @@ static int __inet_insert_ifa(struct in_ifaddr
*ifa, struct nlmsghdr *nlh,
while (ifa1) {
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
- ifa->ifa_scope <= ifa1->ifa_scope)
+ ifa->ifa_scope >= ifa1->ifa_scope)
last_primary = &ifa1->ifa_next;
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa)) {
base-commit: ce6b4d3216b63f902bb8e9695ee6c10c83415f65
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH net-next 2/2] selftests: net: add test for IPv4 address scope ordering
2026-07-20 18:16 [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Tim Wong
@ 2026-07-20 18:21 ` Tim Wong
2026-07-21 9:01 ` [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Ido Schimmel
1 sibling, 0 replies; 3+ messages in thread
From: Tim Wong @ 2026-07-20 18:21 UTC (permalink / raw)
To: netdev; +Cc: dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
linux-kernel
Add a selftest verifying that IPv4 addresses on an interface are
enumerated with global-scope addresses listed before link-scope
addresses, regardless of the order in which the addresses were
configured. This exercises the ordering fixed in the preceding
patch ("ipv4: devinet: list global scope addresses before link
scope addresses") and guards against regression.
Signed-off-by: kanman.wong <kanman.wong@dish.com>
---
tools/testing/selftests/net/Makefile | 1 +
.../selftests/net/fib_ipv4_scope_order.sh | 55 +++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100755 tools/testing/selftests/net/fib_ipv4_scope_order.sh
diff --git a/tools/testing/selftests/net/Makefile
b/tools/testing/selftests/net/Makefile
index 708d960ae07d..66a79c915961 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -33,6 +33,7 @@ TEST_PROGS := \
fdb_flush.sh \
fdb_notify.sh \
fib-onlink-tests.sh \
+ fib_ipv4_scope_order.sh \
fib_nexthop_multiprefix.sh \
fib_nexthop_nongw.sh \
fib_nexthops.sh \
diff --git a/tools/testing/selftests/net/fib_ipv4_scope_order.sh
b/tools/testing/selftests/net/fib_ipv4_scope_order.sh
new file mode 100755
index 000000000000..3bbb7eefa2d8
--- /dev/null
+++ b/tools/testing/selftests/net/fib_ipv4_scope_order.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify IPv4 addresses are enumerated with global-scope addresses
+# listed before link-scope addresses on the same interface,
+# regardless of the order in which they were configured -- matching
+# existing IPv6 address enumeration behavior.
+
+source lib.sh
+
+ret=0
+
+setup() {
+ setup_ns TEST_NS
+ ip -n "$TEST_NS" link add dummy0 type dummy
+ ip -n "$TEST_NS" link set dummy0 up
+}
+
+cleanup() {
+ cleanup_ns "$TEST_NS"
+}
+
+check_order() {
+ local desc="$1"
+ local order
+ local first
+
+ order=$(ip -n "$TEST_NS" -o addr show dev dummy0 | grep -oP
'(?<=scope )(global|link)')
+ first=$(echo "$order" | head -1)
+
+ if [ "$first" != "global" ]; then
+ echo "FAIL: $desc: link-scope address listed before global-scope address"
+ ret=1
+ else
+ echo "PASS: $desc"
+ fi
+}
+
+trap cleanup EXIT
+setup
+
+# Case 1: link-scope address added before global-scope address.
+ip -n "$TEST_NS" addr add 169.254.1.1/16 dev dummy0 scope link
+ip -n "$TEST_NS" addr add 192.0.2.1/24 dev dummy0 scope global
+check_order "link added before global"
+
+ip -n "$TEST_NS" addr flush dev dummy0
+
+# Case 2: global-scope address added before link-scope address
+# (sanity check -- should already pass even without the fix).
+ip -n "$TEST_NS" addr add 192.0.2.1/24 dev dummy0 scope global
+ip -n "$TEST_NS" addr add 169.254.1.1/16 dev dummy0 scope link
+check_order "global added before link"
+
+exit $ret
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses
2026-07-20 18:16 [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Tim Wong
2026-07-20 18:21 ` [PATCH net-next 2/2] selftests: net: add test for IPv4 address scope ordering Tim Wong
@ 2026-07-21 9:01 ` Ido Schimmel
1 sibling, 0 replies; 3+ messages in thread
From: Ido Schimmel @ 2026-07-21 9:01 UTC (permalink / raw)
To: Tim Wong
Cc: netdev, dsahern, davem, edumazet, kuba, pabeni, horms,
linux-kernel
On Mon, Jul 20, 2026 at 12:16:23PM -0600, Tim Wong wrote:
> __inet_insert_ifa() inserts a new primary address by advancing an
> insertion pointer past every existing primary address whose scope
> is >= the new address's scope. Because IPv4 scope values are
> numerically smaller for wider scopes (RT_SCOPE_UNIVERSE < ... <
> RT_SCOPE_LINK < RT_SCOPE_HOST), the comparison
>
> ifa->ifa_scope <= ifa1->ifa_scope
>
> is true for a global-scope new address against essentially every
> existing entry, so the new address is pushed all the way to the
> tail of the primary address list, ending up *after* any link-scope
> addresses that were configured earlier.
>
> On an interface carrying a mix of global- and link-scope IPv4
> addresses (e.g. a routable address alongside an RFC 3927
> 169.254.0.0/16 address, or any address explicitly assigned link
> scope), this makes the resulting order in in_dev->ifa_list -- and
> therefore the order addresses are reported via netlink
> (RTM_GETADDR), ioctl (SIOCGIFCONF), and /proc/net -- depend on
> configuration order rather than scope. Userspace consumers that
> pick the first address returned for an interface (e.g. via
> getifaddrs()) can end up preferring a link-scope address over a
> global one.
It's a user space problem. The kernel provides all the needed
information for user space to make an educated choice.
There was already an attempt to change IPv6's intra-scope order to match
IPv4's and it broke user space:
https://lore.kernel.org/all/20260529112357.5079-1-fmancera@suse.de/
Now you propose changing IPv4's inter-scope order to match IPv6's. It
will most likely break user space and kernel selftests. Please solve
this in user space.
>
> IPv6 already avoids this: ipv6_add_addr() keeps idev->addr_list
> ordered so global-scope addresses precede link-local ones
> regardless of configuration order.
I don't understand the point about configuration order. Only the
intra-scope order is determined by configuration order, no?
>
> Fix the comparison so the insertion pointer only advances past
> addresses that are at least as global as the new one:
>
> ifa->ifa_scope >= ifa1->ifa_scope
>
> This groups global-scope primary addresses ahead of link-scope
> primary addresses in in_dev->ifa_list, preserving insertion order
> within each scope group, and brings IPv4 address enumeration order
> in line with existing IPv6 behavior.
>
> Signed-off-by: kanman.wong <kanman.wong@dish.com>
> ---
> net/ipv4/devinet.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index a35b72662e43..056f2169c6a3 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -510,7 +510,7 @@ static int __inet_insert_ifa(struct in_ifaddr
> *ifa, struct nlmsghdr *nlh,
>
> while (ifa1) {
> if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
> - ifa->ifa_scope <= ifa1->ifa_scope)
> + ifa->ifa_scope >= ifa1->ifa_scope)
> last_primary = &ifa1->ifa_next;
> if (ifa1->ifa_mask == ifa->ifa_mask &&
> inet_ifa_match(ifa1->ifa_address, ifa)) {
The patch is whitespace-damaged.
>
> base-commit: ce6b4d3216b63f902bb8e9695ee6c10c83415f65
> --
> 2.51.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-21 9:01 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 18:16 [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Tim Wong
2026-07-20 18:21 ` [PATCH net-next 2/2] selftests: net: add test for IPv4 address scope ordering Tim Wong
2026-07-21 9:01 ` [PATCH net-next 1/2] ipv4: devinet: list global scope addresses before link scope addresses Ido Schimmel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox