Skip to content

Commit 5b4b62a

Browse files
kuba-moodavem330
authored andcommitted
rtnetlink: make the "split" NLM_DONE handling generic
Jaroslav reports Dell's OMSA Systems Management Data Engine expects NLM_DONE in a separate recvmsg(), both for rtnl_dump_ifinfo() and inet_dump_ifaddr(). We already added a similar fix previously in commit 460b0d3 ("inet: bring NLM_DONE out to a separate recv() again") Instead of modifying all the dump handlers, and making them look different than modern for_each_netdev_dump()-based dump handlers - put the workaround in rtnetlink code. This will also help us move the custom rtnl-locking from af_netlink in the future (in net-next). Note that this change is not touching rtnl_dump_all(). rtnl_dump_all() is different kettle of fish and a potential problem. We now mix families in a single recvmsg(), but NLM_DONE is not coalesced. Tested: ./cli.py --dbg-small-recv 4096 --spec netlink/specs/rt_addr.yaml \ --dump getaddr --json '{"ifa-family": 2}' ./cli.py --dbg-small-recv 4096 --spec netlink/specs/rt_route.yaml \ --dump getroute --json '{"rtm-family": 2}' ./cli.py --dbg-small-recv 4096 --spec netlink/specs/rt_link.yaml \ --dump getlink Fixes: 3e41af9 ("rtnetlink: use xarray iterator to implement rtnl_dump_ifinfo()") Fixes: cdb2f80 ("inet: use xa_array iterator to implement inet_dump_ifaddr()") Reported-by: Jaroslav Pulchart <jaroslav.pulchart@gooddata.com> Link: https://lore.kernel.org/all/CAK8fFZ7MKoFSEzMBDAOjoUt+vTZRRQgLDNXEOfdCCXSoXXKE0g@mail.gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e137596 commit 5b4b62a

File tree

4 files changed

+45
-9
lines changed

4 files changed

+45
-9
lines changed

include/net/rtnetlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum rtnl_link_flags {
1313
RTNL_FLAG_DOIT_UNLOCKED = BIT(0),
1414
RTNL_FLAG_BULK_DEL_SUPPORTED = BIT(1),
1515
RTNL_FLAG_DUMP_UNLOCKED = BIT(2),
16+
RTNL_FLAG_DUMP_SPLIT_NLM_DONE = BIT(3), /* legacy behavior */
1617
};
1718

1819
enum rtnl_kinds {

net/core/rtnetlink.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6484,6 +6484,46 @@ static int rtnl_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
64846484

64856485
/* Process one rtnetlink message. */
64866486

6487+
static int rtnl_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
6488+
{
6489+
rtnl_dumpit_func dumpit = cb->data;
6490+
int err;
6491+
6492+
/* Previous iteration have already finished, avoid calling->dumpit()
6493+
* again, it may not expect to be called after it reached the end.
6494+
*/
6495+
if (!dumpit)
6496+
return 0;
6497+
6498+
err = dumpit(skb, cb);
6499+
6500+
/* Old dump handlers used to send NLM_DONE as in a separate recvmsg().
6501+
* Some applications which parse netlink manually depend on this.
6502+
*/
6503+
if (cb->flags & RTNL_FLAG_DUMP_SPLIT_NLM_DONE) {
6504+
if (err < 0 && err != -EMSGSIZE)
6505+
return err;
6506+
if (!err)
6507+
cb->data = NULL;
6508+
6509+
return skb->len;
6510+
}
6511+
return err;
6512+
}
6513+
6514+
static int rtnetlink_dump_start(struct sock *ssk, struct sk_buff *skb,
6515+
const struct nlmsghdr *nlh,
6516+
struct netlink_dump_control *control)
6517+
{
6518+
if (control->flags & RTNL_FLAG_DUMP_SPLIT_NLM_DONE) {
6519+
WARN_ON(control->data);
6520+
control->data = control->dump;
6521+
control->dump = rtnl_dumpit;
6522+
}
6523+
6524+
return netlink_dump_start(ssk, skb, nlh, control);
6525+
}
6526+
64876527
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
64886528
struct netlink_ext_ack *extack)
64896529
{
@@ -6548,7 +6588,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
65486588
.module = owner,
65496589
.flags = flags,
65506590
};
6551-
err = netlink_dump_start(rtnl, skb, nlh, &c);
6591+
err = rtnetlink_dump_start(rtnl, skb, nlh, &c);
65526592
/* netlink_dump_start() will keep a reference on
65536593
* module if dump is still in progress.
65546594
*/
@@ -6694,7 +6734,7 @@ void __init rtnetlink_init(void)
66946734
register_netdevice_notifier(&rtnetlink_dev_notifier);
66956735

66966736
rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink,
6697-
rtnl_dump_ifinfo, 0);
6737+
rtnl_dump_ifinfo, RTNL_FLAG_DUMP_SPLIT_NLM_DONE);
66986738
rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, 0);
66996739
rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, 0);
67006740
rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, 0);

net/ipv4/devinet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2805,7 +2805,7 @@ void __init devinet_init(void)
28052805
rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, 0);
28062806
rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
28072807
rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr,
2808-
RTNL_FLAG_DUMP_UNLOCKED);
2808+
RTNL_FLAG_DUMP_UNLOCKED | RTNL_FLAG_DUMP_SPLIT_NLM_DONE);
28092809
rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
28102810
inet_netconf_dump_devconf,
28112811
RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED);

net/ipv4/fib_frontend.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,11 +1050,6 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
10501050
e++;
10511051
}
10521052
}
1053-
1054-
/* Don't let NLM_DONE coalesce into a message, even if it could.
1055-
* Some user space expects NLM_DONE in a separate recv().
1056-
*/
1057-
err = skb->len;
10581053
out:
10591054

10601055
cb->args[1] = e;
@@ -1665,5 +1660,5 @@ void __init ip_fib_init(void)
16651660
rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, 0);
16661661
rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, 0);
16671662
rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib,
1668-
RTNL_FLAG_DUMP_UNLOCKED);
1663+
RTNL_FLAG_DUMP_UNLOCKED | RTNL_FLAG_DUMP_SPLIT_NLM_DONE);
16691664
}

0 commit comments

Comments
 (0)