diff options
-rw-r--r-- | net/bridge/br_fdb.c | 15 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 74 |
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 | ||
2536 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2536 | static 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; |