net: ndo_fdb_dump should report -EMSGSIZE to rtnl_fdb_dump.
authorMINOURA Makoto / 箕浦 真 <minoura@valinux.co.jp>
Thu, 25 Feb 2016 05:20:48 +0000 (14:20 +0900)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 Feb 2016 20:04:02 +0000 (15:04 -0500)
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>
drivers/net/vxlan.c
net/bridge/br_fdb.c
net/core/rtnetlink.c
net/switchdev/switchdev.c

index e6944b29588e1bd329c5b331988373d5297c0bd6..b601139a145a99e04e9fa964a53ba8aa6d9a822a 100644 (file)
@@ -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;
                        }
index 82e3e97050173542b5d6094ebc4db81324198b18..dcea4f4c62b3b43d701fb68a74a6aa1a1e0aa8cf 100644 (file)
@@ -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;
                }
index d735e854f916040912fb12930cbc6a7950ace942..8261d95dd846647798c7dba8f1dbfa4cf61a0eef 100644 (file)
@@ -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;
        }
index 47f7da58a7f0e93e3ffd632396a5a8db65c7f7c3..8b5833c1ff2e8695030587749c8c72d86d334323 100644 (file)
@@ -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);