Merge branch 'netlink-fixes-for-cross-namespace-nsid-reporting'

Ilya Maximets says:

====================
netlink: fixes for cross-namespace nsid reporting

While working on some new features for OVS and OVN we discovered that
self-referential NSIDs get unintentionally allocated in the system as
well as unexpectedly reported for local events on all-nsid listeners.

More details in the patches. They change user-visible behavior, but
the current behavior is arguably a bug, as it makes it hard to use
all-nsid sockets without a decent amount of extra unrelated work of
tracking when new NSIDs are allocated for your local namespace.

Tests are added to check the expected behavior and YNL is extended
to support all-nsid sockets in the tests.
====================

Link: https://patch.msgid.link/20260520172317.175168-1-i.maximets@ovn.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-05-22 17:11:11 -07:00
commit f54ea9ba95
2 changed files with 67 additions and 5 deletions

View File

@ -1482,9 +1482,14 @@ static void do_one_broadcast(struct sock *sk,
p->skb2 = NULL;
goto out;
}
NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net);
if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED)
NETLINK_CB(p->skb2).nsid_is_set = true;
NETLINK_CB(p->skb2).nsid_is_set = false;
if (!net_eq(sock_net(sk), p->net)) {
NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net);
if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED)
NETLINK_CB(p->skb2).nsid_is_set = true;
}
val = netlink_broadcast_deliver(sk, p->skb2);
if (val < 0) {
netlink_overrun(sk);

View File

@ -3,13 +3,14 @@
import time
from lib.py import ksft_run, ksft_exit, ksft_true
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_true
from lib.py import ip
from lib.py import NetNS, NetNSEnter
from lib.py import RtnlFamily
LINK_NETNSID = 100
LINK_NETNSID2 = 200
def test_event() -> None:
@ -32,6 +33,57 @@ def test_event() -> None:
"Received unexpected link notification")
def test_event_all_nsid() -> None:
"""NETLINK_LISTEN_ALL_NSID notifications: local events must not
carry nsid even with a self-referential mapping. Remote events
must carry the correct nsid."""
with NetNS() as ns1, NetNS() as ns2:
net1, net2 = str(ns1), str(ns2)
with NetNSEnter(net1):
rtnl = RtnlFamily()
rtnl.ntf_listen_all_nsid()
rtnl.ntf_subscribe("rtnlgrp-link")
# Case 1: no nsid assigned, local event, no nsid expected.
ip("link add dummy-lo type dummy", ns=net1)
# Case 2: self-referential nsid, local event, still no nsid.
ip(f"netns set {net1} {LINK_NETNSID}", ns=net1)
ip("link add dummy-sr type dummy", ns=net1)
# Case 3: remote event, nsid present.
ip(f"netns set {net2} {LINK_NETNSID2}", ns=net1)
ip("link add dummy-re type dummy", ns=net2)
# Collect the three newlink events, ignoring unrelated noise.
events = {}
for msg in rtnl.poll_ntf(duration=1):
if msg['name'] == 'getlink':
ifname = msg['msg'].get('ifname')
if ifname in ('dummy-lo', 'dummy-sr', 'dummy-re'):
events[ifname] = msg
if len(events) == 3:
break
ksft_true('dummy-lo' in events, "missing local event")
ksft_true(events['dummy-lo'].get('nsid') is None,
"local event without nsid should not carry nsid")
ksft_true('dummy-sr' in events, "missing self-ref event")
ksft_true(events['dummy-sr'].get('nsid') is None,
"local event with self-ref nsid should not carry nsid")
ksft_true('dummy-re' in events, "missing remote event")
ksft_eq(events['dummy-re'].get('nsid'), LINK_NETNSID2,
"remote event should carry nsid")
ip("link del dummy-lo", ns=net1)
ip("link del dummy-sr", ns=net1)
ip("link del dummy-re", ns=net2)
def validate_link_netns(netns, ifname, link_netnsid) -> bool:
link_info = ip(f"-d link show dev {ifname}", ns=netns, json=True)
if not link_info:
@ -133,7 +185,12 @@ def test_peer_net() -> None:
def main() -> None:
ksft_run([test_event, test_link_net, test_peer_net])
ksft_run([
test_event,
test_event_all_nsid,
test_link_net,
test_peer_net,
])
ksft_exit()