Skip to content

Commit

Permalink
Merge branch 'bridge-fdb-dump-filter'
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
davem330 committed Jul 10, 2014
2 parents 69b4b7a + 5e6d243 commit 51b5bd1
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 22 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/i40e/i40e_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7095,13 +7095,14 @@ static int i40e_ndo_fdb_del(struct ndmsg *ndm,
static int i40e_ndo_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev,
int idx)
{
struct i40e_netdev_priv *np = netdev_priv(dev);
struct i40e_pf *pf = np->vsi->back;

if (pf->flags & I40E_FLAG_SRIOV_ENABLED)
idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
idx = ndo_dflt_fdb_dump(skb, cb, dev, filter_dev, idx);

return idx;
}
Expand Down
7 changes: 4 additions & 3 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,16 +427,17 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
}

static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
struct net_device *netdev, int idx)
struct net_device *netdev,
struct net_device *filter_dev, int idx)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);

if (!adapter->fdb_mac_learn)
return ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
return ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx);

if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
qlcnic_sriov_check(adapter))
idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
idx = ndo_dflt_fdb_dump(skb, ncb, netdev, filter_dev, idx);

return idx;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,8 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],

/* Dump forwarding table */
static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev, int idx)
struct net_device *dev,
struct net_device *filter_dev, int idx)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
unsigned int h;
Expand Down
4 changes: 3 additions & 1 deletion include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,8 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
* const unsigned char *addr)
* Deletes the FDB entry from dev coresponding to addr.
* int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb,
* struct net_device *dev, int idx)
* struct net_device *dev, struct net_device *filter_dev,
* int idx)
* Used to add FDB entries to dump requests. Implementers should add
* entries to skb and update idx with the number of entries.
*
Expand Down Expand Up @@ -1114,6 +1115,7 @@ struct net_device_ops {
int (*ndo_fdb_dump)(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev,
int idx);

int (*ndo_bridge_setlink)(struct net_device *dev,
Expand Down
1 change: 1 addition & 0 deletions include/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ extern void __rtnl_unlock(void);
extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev,
int idx);
extern int ndo_dflt_fdb_add(struct ndmsg *ndm,
struct nlattr *tb[],
Expand Down
14 changes: 14 additions & 0 deletions net/bridge/br_fdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@ static void fdb_notify(struct net_bridge *br,
int br_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev,
int idx)
{
struct net_bridge *br = netdev_priv(dev);
Expand All @@ -691,6 +692,19 @@ int br_fdb_dump(struct sk_buff *skb,
if (idx < cb->args[0])
goto skip;

if (filter_dev &&
(!f->dst || f->dst->dev != filter_dev)) {
if (filter_dev != dev)
goto skip;
/* !f->dst is a speacial case for bridge
* It means the MAC belongs to the bridge
* Therefore need a little more filtering
* we only want to dump the !f->dst case
*/
if (f->dst)
goto skip;
}

if (fdb_fill_info(skb, br, f,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq,
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev,
const unsigned char *addr, u16 nlh_flags);
int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev, int idx);
struct net_device *dev, struct net_device *fdev, int idx);
int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p);

Expand Down
75 changes: 60 additions & 15 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -2517,6 +2517,7 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev,
int idx)
{
int err;
Expand All @@ -2534,28 +2535,72 @@ EXPORT_SYMBOL(ndo_dflt_fdb_dump);

static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int idx = 0;
struct net *net = sock_net(skb->sk);
struct net_device *dev;
struct nlattr *tb[IFLA_MAX+1];
struct net_device *bdev = NULL;
struct net_device *br_dev = NULL;
const struct net_device_ops *ops = NULL;
const struct net_device_ops *cops = NULL;
struct ifinfomsg *ifm = nlmsg_data(cb->nlh);
struct net *net = sock_net(skb->sk);
int brport_idx = 0;
int br_idx = 0;
int idx = 0;

rcu_read_lock();
for_each_netdev_rcu(net, dev) {
if (dev->priv_flags & IFF_BRIDGE_PORT) {
struct net_device *br_dev;
const struct net_device_ops *ops;
if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
ifla_policy) == 0) {
if (tb[IFLA_MASTER])
br_idx = nla_get_u32(tb[IFLA_MASTER]);
}

brport_idx = ifm->ifi_index;

if (br_idx) {
br_dev = __dev_get_by_index(net, br_idx);
if (!br_dev)
return -ENODEV;

ops = br_dev->netdev_ops;
bdev = br_dev;
}

for_each_netdev(net, dev) {
if (brport_idx && (dev->ifindex != brport_idx))
continue;

if (!br_idx) { /* user did not specify a specific bridge */
if (dev->priv_flags & IFF_BRIDGE_PORT) {
br_dev = netdev_master_upper_dev_get(dev);
cops = br_dev->netdev_ops;
}

br_dev = netdev_master_upper_dev_get(dev);
ops = br_dev->netdev_ops;
if (ops->ndo_fdb_dump)
idx = ops->ndo_fdb_dump(skb, cb, dev, idx);
bdev = dev;
} else {
if (dev != br_dev &&
!(dev->priv_flags & IFF_BRIDGE_PORT))
continue;

if (br_dev != netdev_master_upper_dev_get(dev) &&
!(dev->priv_flags & IFF_EBRIDGE))
continue;

bdev = br_dev;
cops = ops;
}

if (dev->priv_flags & IFF_BRIDGE_PORT) {
if (cops && cops->ndo_fdb_dump)
idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev,
idx);
}

idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx);
if (dev->netdev_ops->ndo_fdb_dump)
idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx);
else
idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, bdev, dev,
idx);

cops = NULL;
}
rcu_read_unlock();

cb->args[0] = idx;
return skb->len;
Expand Down

0 comments on commit 51b5bd1

Please sign in to comment.