Skip to content

Commit 14cf0cd

Browse files
ffmancerakuba-moo
authored andcommitted
ipv4: nexthop: allocate skb dynamically in rtm_get_nexthop()
When querying a nexthop object via RTM_GETNEXTHOP, the kernel currently allocates a fixed-size skb using NLMSG_GOODSIZE. While sufficient for single nexthops and small Equal-Cost Multi-Path groups, this fixed allocation fails for large nexthop groups like 512 nexthops. This results in the following warning splat: WARNING: net/ipv4/nexthop.c:3395 at rtm_get_nexthop+0x176/0x1c0, CPU#20: rep/4608 [...] RIP: 0010:rtm_get_nexthop (net/ipv4/nexthop.c:3395) [...] Call Trace: <TASK> rtnetlink_rcv_msg (net/core/rtnetlink.c:6989) netlink_rcv_skb (net/netlink/af_netlink.c:2550) netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344) netlink_sendmsg (net/netlink/af_netlink.c:1894) ____sys_sendmsg (net/socket.c:721 net/socket.c:736 net/socket.c:2585) ___sys_sendmsg (net/socket.c:2641) __sys_sendmsg (net/socket.c:2671) do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) </TASK> Fix this by allocating the size dynamically using nh_nlmsg_size() and using nlmsg_new(), this is consistent with nexthop_notify() behavior. In addition, adjust nh_nlmsg_size_grp() so it calculates the size needed based on flags passed. While at it, also add the size of NHA_FDB for nexthop group size calculation as it was missing too. This cannot be reproduced via iproute2 as the group size is currently limited and the command fails as follows: addattr_l ERROR: message exceeded bound of 1048 Fixes: 430a049 ("nexthop: Add support for nexthop groups") Reported-by: Yiming Qian <[email protected]> Closes: https://lore.kernel.org/netdev/CAL_bE8Li2h4KO+AQFXW4S6Yb_u5X4oSKnkywW+LPFjuErhqELA@mail.gmail.com/ Signed-off-by: Fernando Fernandez Mancera <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 06aaf04 commit 14cf0cd

1 file changed

Lines changed: 27 additions & 11 deletions

File tree

net/ipv4/nexthop.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,16 +1003,32 @@ static size_t nh_nlmsg_size_grp_res(struct nh_group *nhg)
10031003
nla_total_size_64bit(8);/* NHA_RES_GROUP_UNBALANCED_TIME */
10041004
}
10051005

1006-
static size_t nh_nlmsg_size_grp(struct nexthop *nh)
1006+
static size_t nh_nlmsg_size_grp(struct nexthop *nh, u32 op_flags)
10071007
{
10081008
struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
10091009
size_t sz = sizeof(struct nexthop_grp) * nhg->num_nh;
10101010
size_t tot = nla_total_size(sz) +
1011-
nla_total_size(2); /* NHA_GROUP_TYPE */
1011+
nla_total_size(2) + /* NHA_GROUP_TYPE */
1012+
nla_total_size(0); /* NHA_FDB */
10121013

10131014
if (nhg->resilient)
10141015
tot += nh_nlmsg_size_grp_res(nhg);
10151016

1017+
if (op_flags & NHA_OP_FLAG_DUMP_STATS) {
1018+
tot += nla_total_size(0) + /* NHA_GROUP_STATS */
1019+
nla_total_size(4); /* NHA_HW_STATS_ENABLE */
1020+
tot += nhg->num_nh *
1021+
(nla_total_size(0) + /* NHA_GROUP_STATS_ENTRY */
1022+
nla_total_size(4) + /* NHA_GROUP_STATS_ENTRY_ID */
1023+
nla_total_size_64bit(8)); /* NHA_GROUP_STATS_ENTRY_PACKETS */
1024+
1025+
if (op_flags & NHA_OP_FLAG_DUMP_HW_STATS) {
1026+
tot += nhg->num_nh *
1027+
nla_total_size_64bit(8); /* NHA_GROUP_STATS_ENTRY_PACKETS_HW */
1028+
tot += nla_total_size(4); /* NHA_HW_STATS_USED */
1029+
}
1030+
}
1031+
10161032
return tot;
10171033
}
10181034

@@ -1047,14 +1063,14 @@ static size_t nh_nlmsg_size_single(struct nexthop *nh)
10471063
return sz;
10481064
}
10491065

1050-
static size_t nh_nlmsg_size(struct nexthop *nh)
1066+
static size_t nh_nlmsg_size(struct nexthop *nh, u32 op_flags)
10511067
{
10521068
size_t sz = NLMSG_ALIGN(sizeof(struct nhmsg));
10531069

10541070
sz += nla_total_size(4); /* NHA_ID */
10551071

10561072
if (nh->is_group)
1057-
sz += nh_nlmsg_size_grp(nh) +
1073+
sz += nh_nlmsg_size_grp(nh, op_flags) +
10581074
nla_total_size(4) + /* NHA_OP_FLAGS */
10591075
0;
10601076
else
@@ -1070,7 +1086,7 @@ static void nexthop_notify(int event, struct nexthop *nh, struct nl_info *info)
10701086
struct sk_buff *skb;
10711087
int err = -ENOBUFS;
10721088

1073-
skb = nlmsg_new(nh_nlmsg_size(nh), gfp_any());
1089+
skb = nlmsg_new(nh_nlmsg_size(nh, 0), gfp_any());
10741090
if (!skb)
10751091
goto errout;
10761092

@@ -3376,15 +3392,15 @@ static int rtm_get_nexthop(struct sk_buff *in_skb, struct nlmsghdr *nlh,
33763392
if (err)
33773393
return err;
33783394

3379-
err = -ENOBUFS;
3380-
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
3381-
if (!skb)
3382-
goto out;
3383-
33843395
err = -ENOENT;
33853396
nh = nexthop_find_by_id(net, id);
33863397
if (!nh)
3387-
goto errout_free;
3398+
goto out;
3399+
3400+
err = -ENOBUFS;
3401+
skb = nlmsg_new(nh_nlmsg_size(nh, op_flags), GFP_KERNEL);
3402+
if (!skb)
3403+
goto out;
33883404

33893405
err = nh_fill_node(skb, nh, RTM_NEWNEXTHOP, NETLINK_CB(in_skb).portid,
33903406
nlh->nlmsg_seq, 0, op_flags);

0 commit comments

Comments
 (0)