net: ndo_fdb_dump should report -EMSGSIZE to rtnl_fdb_dump.
When the send skbuff reaches the end, nlmsg_put and friends returns -EMSGSIZE but it is silently thrown away in ndo_fdb_dump. It is called within a for_each_netdev loop and the first fdb entry of a following netdev could fit in the remaining skbuff. This breaks the mechanism of cb->args[0] and idx to keep track of the entries that are already dumped, which results missing entries in bridge fdb show command. Signed-off-by: Minoura Makoto <minoura@valinux.co.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
4c0b6eaf37
Коммит
472681d57a
|
@ -931,8 +931,10 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
cb->nlh->nlmsg_seq,
|
||||
RTM_NEWNEIGH,
|
||||
NLM_F_MULTI, rd);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
cb->args[1] = err;
|
||||
goto out;
|
||||
}
|
||||
skip:
|
||||
++idx;
|
||||
}
|
||||
|
|
|
@ -723,6 +723,8 @@ int br_fdb_dump(struct sk_buff *skb,
|
|||
struct net_bridge_fdb_entry *f;
|
||||
|
||||
hlist_for_each_entry_rcu(f, &br->hash[i], hlist) {
|
||||
int err;
|
||||
|
||||
if (idx < cb->args[0])
|
||||
goto skip;
|
||||
|
||||
|
@ -741,12 +743,15 @@ int br_fdb_dump(struct sk_buff *skb,
|
|||
if (!filter_dev && f->dst)
|
||||
goto skip;
|
||||
|
||||
if (fdb_fill_info(skb, br, f,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
RTM_NEWNEIGH,
|
||||
NLM_F_MULTI) < 0)
|
||||
err = fdb_fill_info(skb, br, f,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
RTM_NEWNEIGH,
|
||||
NLM_F_MULTI);
|
||||
if (err < 0) {
|
||||
cb->args[1] = err;
|
||||
break;
|
||||
}
|
||||
skip:
|
||||
++idx;
|
||||
}
|
||||
|
|
|
@ -2911,6 +2911,7 @@ int ndo_dflt_fdb_dump(struct sk_buff *skb,
|
|||
nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->mc);
|
||||
out:
|
||||
netif_addr_unlock_bh(dev);
|
||||
cb->args[1] = err;
|
||||
return idx;
|
||||
}
|
||||
EXPORT_SYMBOL(ndo_dflt_fdb_dump);
|
||||
|
@ -2944,6 +2945,7 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
ops = br_dev->netdev_ops;
|
||||
}
|
||||
|
||||
cb->args[1] = 0;
|
||||
for_each_netdev(net, dev) {
|
||||
if (brport_idx && (dev->ifindex != brport_idx))
|
||||
continue;
|
||||
|
@ -2971,12 +2973,16 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev,
|
||||
idx);
|
||||
}
|
||||
if (cb->args[1] == -EMSGSIZE)
|
||||
break;
|
||||
|
||||
if (dev->netdev_ops->ndo_fdb_dump)
|
||||
idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL,
|
||||
idx);
|
||||
else
|
||||
idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx);
|
||||
if (cb->args[1] == -EMSGSIZE)
|
||||
break;
|
||||
|
||||
cops = NULL;
|
||||
}
|
||||
|
|
|
@ -1093,8 +1093,11 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
.cb = cb,
|
||||
.idx = idx,
|
||||
};
|
||||
int err;
|
||||
|
||||
switchdev_port_obj_dump(dev, &dump.fdb.obj, switchdev_port_fdb_dump_cb);
|
||||
err = switchdev_port_obj_dump(dev, &dump.fdb.obj,
|
||||
switchdev_port_fdb_dump_cb);
|
||||
cb->args[1] = err;
|
||||
return dump.idx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump);
|
||||
|
|
Загрузка…
Ссылка в новой задаче