aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_fdb.c15
-rw-r--r--net/core/rtnetlink.c74
2 files changed, 70 insertions, 19 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 6edecd11ecf0..0bb9d8b63dd2 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -692,9 +692,18 @@ int br_fdb_dump(struct sk_buff *skb,
692 if (idx < cb->args[0]) 692 if (idx < cb->args[0])
693 goto skip; 693 goto skip;
694 694
695 if (filter_dev && (!f->dst || !f->dst->dev || 695 if (filter_dev &&
696 f->dst->dev != filter_dev)) 696 (!f->dst || f->dst->dev != filter_dev)) {
697 goto skip; 697 if (filter_dev != dev)
698 goto skip;
699 /* !f->dst is a speacial case for bridge
700 * It means the MAC belongs to the bridge
701 * Therefore need a little more filtering
702 * we only want to dump the !f->dst case
703 */
704 if (f->dst)
705 goto skip;
706 }
698 707
699 if (fdb_fill_info(skb, br, f, 708 if (fdb_fill_info(skb, br, f,
700 NETLINK_CB(cb->skb).portid, 709 NETLINK_CB(cb->skb).portid,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 90a906e7ac26..1f8a59e02c48 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2535,30 +2535,72 @@ EXPORT_SYMBOL(ndo_dflt_fdb_dump);
2535 2535
2536static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) 2536static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
2537{ 2537{
2538 int idx = 0;
2539 struct net *net = sock_net(skb->sk);
2540 struct net_device *dev; 2538 struct net_device *dev;
2539 struct nlattr *tb[IFLA_MAX+1];
2540 struct net_device *bdev = NULL;
2541 struct net_device *br_dev = NULL;
2542 const struct net_device_ops *ops = NULL;
2543 const struct net_device_ops *cops = NULL;
2544 struct ifinfomsg *ifm = nlmsg_data(cb->nlh);
2545 struct net *net = sock_net(skb->sk);
2546 int brport_idx = 0;
2547 int br_idx = 0;
2548 int idx = 0;
2549
2550 if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
2551 ifla_policy) == 0) {
2552 if (tb[IFLA_MASTER])
2553 br_idx = nla_get_u32(tb[IFLA_MASTER]);
2554 }
2555
2556 brport_idx = ifm->ifi_index;
2557
2558 if (br_idx) {
2559 br_dev = __dev_get_by_index(net, br_idx);
2560 if (!br_dev)
2561 return -ENODEV;
2562
2563 ops = br_dev->netdev_ops;
2564 bdev = br_dev;
2565 }
2566
2567 for_each_netdev(net, dev) {
2568 if (brport_idx && (dev->ifindex != brport_idx))
2569 continue;
2570
2571 if (!br_idx) { /* user did not specify a specific bridge */
2572 if (dev->priv_flags & IFF_BRIDGE_PORT) {
2573 br_dev = netdev_master_upper_dev_get(dev);
2574 cops = br_dev->netdev_ops;
2575 }
2576
2577 bdev = dev;
2578 } else {
2579 if (dev != br_dev &&
2580 !(dev->priv_flags & IFF_BRIDGE_PORT))
2581 continue;
2582
2583 if (br_dev != netdev_master_upper_dev_get(dev) &&
2584 !(dev->priv_flags & IFF_EBRIDGE))
2585 continue;
2586
2587 bdev = br_dev;
2588 cops = ops;
2589 }
2541 2590
2542 rcu_read_lock();
2543 for_each_netdev_rcu(net, dev) {
2544 if (dev->priv_flags & IFF_BRIDGE_PORT) { 2591 if (dev->priv_flags & IFF_BRIDGE_PORT) {
2545 struct net_device *br_dev; 2592 if (cops && cops->ndo_fdb_dump)
2546 const struct net_device_ops *ops; 2593 idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev,
2547 2594 idx);
2548 br_dev = netdev_master_upper_dev_get(dev);
2549 ops = br_dev->netdev_ops;
2550 if (ops->ndo_fdb_dump)
2551 idx = ops->ndo_fdb_dump(skb, cb, dev, NULL,
2552 idx);
2553 } 2595 }
2554 2596
2597 idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx);
2555 if (dev->netdev_ops->ndo_fdb_dump) 2598 if (dev->netdev_ops->ndo_fdb_dump)
2556 idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL, 2599 idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev,
2557 idx); 2600 idx);
2558 else 2601
2559 idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); 2602 cops = NULL;
2560 } 2603 }
2561 rcu_read_unlock();
2562 2604
2563 cb->args[0] = idx; 2605 cb->args[0] = idx;
2564 return skb->len; 2606 return skb->len;