Skip to content

Commit e93fb3e

Browse files
jrfastabdavem330
authored andcommitted
net: route dump netlink NLM_F_MULTI flag missing
An excerpt from netlink(7) man page, In multipart messages (multiple nlmsghdr headers with associated payload in one byte stream) the first and all following headers have the NLM_F_MULTI flag set, except for the last header which has the type NLMSG_DONE. but, after (ee28906) there is a missing NLM_F_MULTI flag in the middle of a FIB dump. The result is user space applications following above man page excerpt may get confused and may stop parsing msg believing something went wrong. In the golang netlink lib [0] the library logic stops parsing believing the message is not a multipart message. Found this running Cilium[1] against net-next while adding a feature to auto-detect routes. I noticed with multiple route tables we no longer could detect the default routes on net tree kernels because the library logic was not returning them. Fix this by handling the fib_dump_info_fnhe() case the same way the fib_dump_info() handles it by passing the flags argument through the call chain and adding a flags argument to rt_fill_info(). Tested with Cilium stack and auto-detection of routes works again. Also annotated libs to dump netlink msgs and inspected NLM_F_MULTI and NLMSG_DONE flags look correct after this. Note: In inet_rtm_getroute() pass rt_fill_info() '0' for flags the same as is done for fib_dump_info() so this looks correct to me. [0] https://github.com/vishvananda/netlink/ [1] https://github.com/cilium/ Fixes: ee28906 ("ipv4: Dump route exceptions if requested") Signed-off-by: John Fastabend <[email protected]> Reviewed-by: Stefano Brivio <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 292a50e commit e93fb3e

File tree

3 files changed

+12
-9
lines changed

3 files changed

+12
-9
lines changed

include/net/route.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ void rt_del_uncached_list(struct rtable *rt);
233233

234234
int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
235235
u32 table_id, struct fib_info *fi,
236-
int *fa_index, int fa_start);
236+
int *fa_index, int fa_start, unsigned int flags);
237237

238238
static inline void ip_rt_put(struct rtable *rt)
239239
{

net/ipv4/fib_trie.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2145,7 +2145,7 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
21452145

21462146
if (filter->dump_exceptions) {
21472147
err = fib_dump_info_fnhe(skb, cb, tb->tb_id, fi,
2148-
&i_fa, s_fa);
2148+
&i_fa, s_fa, flags);
21492149
if (err < 0)
21502150
goto stop;
21512151
}

net/ipv4/route.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2728,15 +2728,16 @@ EXPORT_SYMBOL_GPL(ip_route_output_flow);
27282728
/* called with rcu_read_lock held */
27292729
static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
27302730
struct rtable *rt, u32 table_id, struct flowi4 *fl4,
2731-
struct sk_buff *skb, u32 portid, u32 seq)
2731+
struct sk_buff *skb, u32 portid, u32 seq,
2732+
unsigned int flags)
27322733
{
27332734
struct rtmsg *r;
27342735
struct nlmsghdr *nlh;
27352736
unsigned long expires = 0;
27362737
u32 error;
27372738
u32 metrics[RTAX_MAX];
27382739

2739-
nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*r), 0);
2740+
nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*r), flags);
27402741
if (!nlh)
27412742
return -EMSGSIZE;
27422743

@@ -2860,7 +2861,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
28602861
static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
28612862
struct netlink_callback *cb, u32 table_id,
28622863
struct fnhe_hash_bucket *bucket, int genid,
2863-
int *fa_index, int fa_start)
2864+
int *fa_index, int fa_start, unsigned int flags)
28642865
{
28652866
int i;
28662867

@@ -2891,7 +2892,7 @@ static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
28912892
err = rt_fill_info(net, fnhe->fnhe_daddr, 0, rt,
28922893
table_id, NULL, skb,
28932894
NETLINK_CB(cb->skb).portid,
2894-
cb->nlh->nlmsg_seq);
2895+
cb->nlh->nlmsg_seq, flags);
28952896
if (err)
28962897
return err;
28972898
next:
@@ -2904,7 +2905,7 @@ static int fnhe_dump_bucket(struct net *net, struct sk_buff *skb,
29042905

29052906
int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
29062907
u32 table_id, struct fib_info *fi,
2907-
int *fa_index, int fa_start)
2908+
int *fa_index, int fa_start, unsigned int flags)
29082909
{
29092910
struct net *net = sock_net(cb->skb->sk);
29102911
int nhsel, genid = fnhe_genid(net);
@@ -2922,7 +2923,8 @@ int fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
29222923
err = 0;
29232924
if (bucket)
29242925
err = fnhe_dump_bucket(net, skb, cb, table_id, bucket,
2925-
genid, fa_index, fa_start);
2926+
genid, fa_index, fa_start,
2927+
flags);
29262928
rcu_read_unlock();
29272929
if (err)
29282930
return err;
@@ -3183,7 +3185,8 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
31833185
fl4.flowi4_tos, res.fi, 0);
31843186
} else {
31853187
err = rt_fill_info(net, dst, src, rt, table_id, &fl4, skb,
3186-
NETLINK_CB(in_skb).portid, nlh->nlmsg_seq);
3188+
NETLINK_CB(in_skb).portid,
3189+
nlh->nlmsg_seq, 0);
31873190
}
31883191
if (err < 0)
31893192
goto errout_rcu;

0 commit comments

Comments
 (0)