Thread (3 messages) flat view 3 messages, 3 authors, 2d ago
WARM2d

[PATCH net-next] selftests: net: add IPv4 and IPv6 same scope address order check

From: Martin Jabůrek <hidden>
Date: 2026-09-01 08:22:31
Subsystem: kernel selftest framework, networking [general], the rest · Maintainers: Shuah Khan, Shuah Khan, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Introduce two new tests `ipv4_verify_addr_order` and
`ipv6_verify_addr_order`, to check the ordering of
a set of IP addresses after insertion.

The implementations of these protocols are inconsistent
in regard to address ordering. IPv4 addresses stay in the
same order as inserted while IPv6 addresses appear in
reverse order. This incosistency has prompted attempts
to unify the ordering, so both protocols act the same
(as IPv4). This however caused user-space regressions in
certain applications, which relied on the order as it
was prior to the change (particularly NetworkManager).

The addition of these tests aims to consolidate the
behaviour to prevent regressions in the future.
The expected behaviour is the initial one, where each
protocol acts differently.

Tests were verified on a recent commit with the expected
behaviour (61eb236c41c2) and a commit making both protocols
act the same way (cb3de96eea66). Tests respectively pass
and not pass as expected.

Conversations detailing the decision process for creating
these tests are linked below.

Link: https://lore.kernel.org/netdev/20260521135310.GC977@cmadams.net/ (local)
Link: https://lore.kernel.org/netdev/20260529112357.5079-1-fmancera@suse.de/ (local)
Suggested-by: Fernando Fernandez Mancera <redacted>
Signed-off-by: Martin Jabůrek <redacted>
---
 tools/testing/selftests/net/rtnetlink.py | 58 +++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/rtnetlink.py b/tools/testing/selftests/net/rtnetlink.py
index 5cc3ebdcf08d..1ee604e4e5f6 100755
--- a/tools/testing/selftests/net/rtnetlink.py
+++ b/tools/testing/selftests/net/rtnetlink.py
@@ -314,11 +314,67 @@ def ipv6_route_del_reason_absent() -> None:
                         "user deletion must not carry del-reason")
 
 
+def ipv4_verify_addr_order() -> None:
+    """
+    After inserting multiple same scope IPv4 addresses, their order
+    must be the same as the insertion order.
+
+    See function ipv6_verify_addr_order in this file for further details.
+    """
+
+    DEV_NAME = "dummy_dev"
+    TEST_ADDRESSES = ["192.0.2.1", "192.0.2.2", "192.0.2.3"]
+
+    with NetNS() as ns:
+        with NetNSEnter(str(ns)):
+            ip(f"link add name {DEV_NAME} type dummy", ns=str(ns))
+            for addr in TEST_ADDRESSES:
+                ip(f"address add {addr}/24 dev {DEV_NAME}", ns=str(ns))
+            ip(f"link set dev {DEV_NAME} up", ns=str(ns))
+
+            rtnl = RtnlAddrFamily()
+            addrs = rtnl.getaddr({"ifa-family": socket.AF_INET}, dump=True)
+            address_list = [addr["address"] for addr in addrs]
+
+            ksft_eq(TEST_ADDRESSES, address_list, "Incorrect IPv4 address order")
+
+
+def ipv6_verify_addr_order() -> None:
+    """
+    After inserting multiple same scope IPv6 addresses, their order
+    must be the _reverse_ of the insertion order.
+
+    While this behaviour is different from how IPv4 acts,
+    updating the IPv6 implementation to act the same way
+    has proved to cause user-space application regressions
+    (particularly in NetworkManager). This behaviour is being
+    tested for to consolidate it as being expected and correct.
+    """
+
+    DEV_NAME = "dummy_dev"
+    TEST_ADDRESSES = ["2001:db8::1", "2001:db8::2", "2001:db8::3"]
+
+    with NetNS() as ns:
+        with NetNSEnter(str(ns)):
+            ip(f"link add name {DEV_NAME} type dummy", ns=str(ns))
+            for addr in TEST_ADDRESSES:
+                ip(f"address add {addr}/32 dev {DEV_NAME}", ns=str(ns))
+            ip(f"link set dev {DEV_NAME} up", ns=str(ns))
+
+            rtnl = RtnlAddrFamily()
+            addrs = rtnl.getaddr({"ifa-family": socket.AF_INET6}, dump=True)
+            address_list = [addr["address"] for addr in addrs]
+
+            # We ignore the link-local address present by default.
+            ksft_eq(TEST_ADDRESSES[::-1], address_list[:3], "Incorrect IPv6 address order")
+
+
 def main() -> None:
     ksft_run([dump_mcaddr_check, dump_mcaddr6_check, ipv4_devconf_notify,
               ipv6_route_del_reason_expired,
               ipv6_route_del_reason_ra_withdrawn,
-              ipv6_route_del_reason_absent])
+              ipv6_route_del_reason_absent,
+              ipv4_verify_addr_order, ipv6_verify_addr_order])
     ksft_exit()
 
 if __name__ == "__main__":
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help