Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'bridge-fdb-dump-filter'

Jamal Hadi Salim says:

====================
bridge: fdb dumping takes a filter device

v7:
Vxlan driver was not updated with new API. Found by DaveM

v6:
Missed checkpatch > 80 chars lines found by Varka Bhadram

v5:
Embarassing qlnic compile failure found by DaveM

v4:
Request from DaveM to use proper comment tagging and remove if-stmnt braces

V3:
Suggestion from Eric D. to use for_each_netdev
Suggestion from Stephen H. to reduce level of indentation

V2:
Suggestions from Vlad
Get rid of rcu read lock since rtnl_lock is being held
simplify for readability
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+87 -22
+2 -1
drivers/net/ethernet/intel/i40e/i40e_main.c
··· 7095 7095 static int i40e_ndo_fdb_dump(struct sk_buff *skb, 7096 7096 struct netlink_callback *cb, 7097 7097 struct net_device *dev, 7098 + struct net_device *filter_dev, 7098 7099 int idx) 7099 7100 { 7100 7101 struct i40e_netdev_priv *np = netdev_priv(dev); 7101 7102 struct i40e_pf *pf = np->vsi->back; 7102 7103 7103 7104 if (pf->flags & I40E_FLAG_SRIOV_ENABLED) 7104 - idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); 7105 + idx = ndo_dflt_fdb_dump(skb, cb, dev, filter_dev, idx); 7105 7106 7106 7107 return idx; 7107 7108 }
+4 -3
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
··· 427 427 } 428 428 429 429 static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb, 430 - struct net_device *netdev, int idx) 430 + struct net_device *netdev, 431 + struct net_device *filter_dev, int idx) 431 432 { 432 433 struct qlcnic_adapter *adapter = netdev_priv(netdev); 433 434 434 435 if (!adapter->fdb_mac_learn) 435 - return ndo_dflt_fdb_dump(skb, ncb, netdev, idx); 436 + return ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); 436 437 437 438 if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || 438 439 qlcnic_sriov_check(adapter)) 439 - idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx); 440 + idx = ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx); 440 441 441 442 return idx; 442 443 }
+2 -1
drivers/net/vxlan.c
··· 933 933 934 934 /* Dump forwarding table */ 935 935 static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, 936 - struct net_device *dev, int idx) 936 + struct net_device *dev, 937 + struct net_device *filter_dev, int idx) 937 938 { 938 939 struct vxlan_dev *vxlan = netdev_priv(dev); 939 940 unsigned int h;
+3 -1
include/linux/netdevice.h
··· 943 943 * const unsigned char *addr) 944 944 * Deletes the FDB entry from dev coresponding to addr. 945 945 * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, 946 - * struct net_device *dev, int idx) 946 + * struct net_device *dev, struct net_device *filter_dev, 947 + * int idx) 947 948 * Used to add FDB entries to dump requests. Implementers should add 948 949 * entries to skb and update idx with the number of entries. 949 950 * ··· 1115 1114 int (*ndo_fdb_dump)(struct sk_buff *skb, 1116 1115 struct netlink_callback *cb, 1117 1116 struct net_device *dev, 1117 + struct net_device *filter_dev, 1118 1118 int idx); 1119 1119 1120 1120 int (*ndo_bridge_setlink)(struct net_device *dev,
+1
include/linux/rtnetlink.h
··· 78 78 extern int ndo_dflt_fdb_dump(struct sk_buff *skb, 79 79 struct netlink_callback *cb, 80 80 struct net_device *dev, 81 + struct net_device *filter_dev, 81 82 int idx); 82 83 extern int ndo_dflt_fdb_add(struct ndmsg *ndm, 83 84 struct nlattr *tb[],
+14
net/bridge/br_fdb.c
··· 676 676 int br_fdb_dump(struct sk_buff *skb, 677 677 struct netlink_callback *cb, 678 678 struct net_device *dev, 679 + struct net_device *filter_dev, 679 680 int idx) 680 681 { 681 682 struct net_bridge *br = netdev_priv(dev); ··· 691 690 hlist_for_each_entry_rcu(f, &br->hash[i], hlist) { 692 691 if (idx < cb->args[0]) 693 692 goto skip; 693 + 694 + if (filter_dev && 695 + (!f->dst || f->dst->dev != filter_dev)) { 696 + if (filter_dev != dev) 697 + goto skip; 698 + /* !f->dst is a speacial case for bridge 699 + * It means the MAC belongs to the bridge 700 + * Therefore need a little more filtering 701 + * we only want to dump the !f->dst case 702 + */ 703 + if (f->dst) 704 + goto skip; 705 + } 694 706 695 707 if (fdb_fill_info(skb, br, f, 696 708 NETLINK_CB(cb->skb).portid,
+1 -1
net/bridge/br_private.h
··· 399 399 int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, 400 400 const unsigned char *addr, u16 nlh_flags); 401 401 int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, 402 - struct net_device *dev, int idx); 402 + struct net_device *dev, struct net_device *fdev, int idx); 403 403 int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); 404 404 void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); 405 405
+60 -15
net/core/rtnetlink.c
··· 2517 2517 int ndo_dflt_fdb_dump(struct sk_buff *skb, 2518 2518 struct netlink_callback *cb, 2519 2519 struct net_device *dev, 2520 + struct net_device *filter_dev, 2520 2521 int idx) 2521 2522 { 2522 2523 int err; ··· 2535 2534 2536 2535 static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) 2537 2536 { 2538 - int idx = 0; 2539 - struct net *net = sock_net(skb->sk); 2540 2537 struct net_device *dev; 2538 + struct nlattr *tb[IFLA_MAX+1]; 2539 + struct net_device *bdev = NULL; 2540 + struct net_device *br_dev = NULL; 2541 + const struct net_device_ops *ops = NULL; 2542 + const struct net_device_ops *cops = NULL; 2543 + struct ifinfomsg *ifm = nlmsg_data(cb->nlh); 2544 + struct net *net = sock_net(skb->sk); 2545 + int brport_idx = 0; 2546 + int br_idx = 0; 2547 + int idx = 0; 2541 2548 2542 - rcu_read_lock(); 2543 - for_each_netdev_rcu(net, dev) { 2544 - if (dev->priv_flags & IFF_BRIDGE_PORT) { 2545 - struct net_device *br_dev; 2546 - const struct net_device_ops *ops; 2549 + if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, 2550 + ifla_policy) == 0) { 2551 + if (tb[IFLA_MASTER]) 2552 + br_idx = nla_get_u32(tb[IFLA_MASTER]); 2553 + } 2547 2554 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, idx); 2555 + brport_idx = ifm->ifi_index; 2556 + 2557 + if (br_idx) { 2558 + br_dev = __dev_get_by_index(net, br_idx); 2559 + if (!br_dev) 2560 + return -ENODEV; 2561 + 2562 + ops = br_dev->netdev_ops; 2563 + bdev = br_dev; 2564 + } 2565 + 2566 + for_each_netdev(net, dev) { 2567 + if (brport_idx && (dev->ifindex != brport_idx)) 2568 + continue; 2569 + 2570 + if (!br_idx) { /* user did not specify a specific bridge */ 2571 + if (dev->priv_flags & IFF_BRIDGE_PORT) { 2572 + br_dev = netdev_master_upper_dev_get(dev); 2573 + cops = br_dev->netdev_ops; 2574 + } 2575 + 2576 + bdev = dev; 2577 + } else { 2578 + if (dev != br_dev && 2579 + !(dev->priv_flags & IFF_BRIDGE_PORT)) 2580 + continue; 2581 + 2582 + if (br_dev != netdev_master_upper_dev_get(dev) && 2583 + !(dev->priv_flags & IFF_EBRIDGE)) 2584 + continue; 2585 + 2586 + bdev = br_dev; 2587 + cops = ops; 2552 2588 } 2553 2589 2590 + if (dev->priv_flags & IFF_BRIDGE_PORT) { 2591 + if (cops && cops->ndo_fdb_dump) 2592 + idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev, 2593 + idx); 2594 + } 2595 + 2596 + idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); 2554 2597 if (dev->netdev_ops->ndo_fdb_dump) 2555 - idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); 2556 - else 2557 - idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); 2598 + idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev, 2599 + idx); 2600 + 2601 + cops = NULL; 2558 2602 } 2559 - rcu_read_unlock(); 2560 2603 2561 2604 cb->args[0] = idx; 2562 2605 return skb->len;