From b7485f6b035a87685ce35e0e52deee6467811eb0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:13 +0100 Subject: neigh: sort Neighbor Cache Entry Flags Suggested-by: Florian Fainelli Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/uapi/linux/neighbour.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index 4a1d7e96dfe3..2f043af7fcd6 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -35,11 +35,10 @@ enum { */ #define NTF_USE 0x01 -#define NTF_PROXY 0x08 /* == ATF_PUBL */ -#define NTF_ROUTER 0x80 - #define NTF_SELF 0x02 #define NTF_MASTER 0x04 +#define NTF_PROXY 0x08 /* == ATF_PUBL */ +#define NTF_ROUTER 0x80 /* * Neighbor Cache Entry States. -- cgit v1.2.3 From f6f6424ba773da6221ecaaa70973eb4dacfa03b2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:15 +0100 Subject: net: make vid as a parameter for ndo_fdb_add/ndo_fdb_del Do the work of parsing NDA_VLAN directly in rtnetlink code, pass simple u16 vid to drivers from there. Signed-off-by: Jiri Pirko Acked-by: Andy Gospodarek Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 9 +++-- drivers/net/macvlan.c | 4 +- drivers/net/vxlan.c | 4 +- include/linux/netdevice.h | 8 ++-- include/linux/rtnetlink.h | 6 ++- net/bridge/br_fdb.c | 39 ++---------------- net/bridge/br_private.h | 4 +- net/core/rtnetlink.c | 50 ++++++++++++++++++++---- 10 files changed, 70 insertions(+), 60 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7262077ad547..5ed5e4036dd9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7536,7 +7536,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev, */ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, + const unsigned char *addr, u16 vid, u16 flags) { struct i40e_netdev_priv *np = netdev_priv(dev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 52776f9e1f71..74aadeb56ada 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7708,7 +7708,7 @@ static int ixgbe_set_features(struct net_device *netdev, static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, + const unsigned char *addr, u16 vid, u16 flags) { /* guarantee we can provide a unique filter for the unicast address */ @@ -7717,7 +7717,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -ENOMEM; } - return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags); + return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags); } static int ixgbe_ndo_bridge_setlink(struct net_device *dev, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index a913b3ad2f89..3227c8063edd 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -376,13 +376,14 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) } static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *netdev, const unsigned char *addr) + struct net_device *netdev, + const unsigned char *addr, u16 vid) { struct qlcnic_adapter *adapter = netdev_priv(netdev); int err = -EOPNOTSUPP; if (!adapter->fdb_mac_learn) - return ndo_dflt_fdb_del(ndm, tb, netdev, addr); + return ndo_dflt_fdb_del(ndm, tb, netdev, addr, vid); if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || qlcnic_sriov_check(adapter)) { @@ -401,13 +402,13 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *netdev, - const unsigned char *addr, u16 flags) + const unsigned char *addr, u16 vid, u16 flags) { struct qlcnic_adapter *adapter = netdev_priv(netdev); int err = 0; if (!adapter->fdb_mac_learn) - return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags); + return ndo_dflt_fdb_add(ndm, tb, netdev, addr, vid, flags); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) && !qlcnic_sriov_check(adapter)) { diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 11d4b3506d6e..9538674587aa 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -873,7 +873,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, + const unsigned char *addr, u16 vid, u16 flags) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -898,7 +898,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr) + const unsigned char *addr, u16 vid) { struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index d802a1ae4560..31ecb03368c6 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -849,7 +849,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, /* Add static entry (via netlink) */ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 flags) + const unsigned char *addr, u16 vid, u16 flags) { struct vxlan_dev *vxlan = netdev_priv(dev); /* struct net *net = dev_net(vxlan->dev); */ @@ -885,7 +885,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], /* Delete entry (via netlink) */ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr) + const unsigned char *addr, u16 vid) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_fdb *f; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2cb772495f7a..589929cf4700 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -951,11 +951,11 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * * int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[], * struct net_device *dev, - * const unsigned char *addr, u16 flags) + * const unsigned char *addr, u16 vid, u16 flags) * Adds an FDB entry to dev for addr. * int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[], * struct net_device *dev, - * const unsigned char *addr) + * const unsigned char *addr, u16 vid) * 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, struct net_device *filter_dev, @@ -1128,11 +1128,13 @@ struct net_device_ops { struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, + u16 vid, u16 flags); int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr); + const unsigned char *addr, + u16 vid); int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 6cacbce1a06c..063f0f581fe0 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -94,11 +94,13 @@ extern int ndo_dflt_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, - u16 flags); + u16 vid, + u16 flags); extern int ndo_dflt_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr); + const unsigned char *addr, + u16 vid); extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u16 mode); diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 08ef4e7a2439..b1be971eb06c 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -805,33 +805,17 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p, /* Add new permanent fdb entry with RTM_NEWNEIGH */ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 nlh_flags) + const unsigned char *addr, u16 vid, u16 nlh_flags) { struct net_bridge_port *p; int err = 0; struct net_port_vlans *pv; - unsigned short vid = VLAN_N_VID; if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) { pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state); return -EINVAL; } - if (tb[NDA_VLAN]) { - if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) { - pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n"); - return -EINVAL; - } - - vid = nla_get_u16(tb[NDA_VLAN]); - - if (!vid || vid >= VLAN_VID_MASK) { - pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", - vid); - return -EINVAL; - } - } - if (is_zero_ether_addr(addr)) { pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n"); return -EINVAL; @@ -845,7 +829,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], } pv = nbp_get_vlan_info(p); - if (vid != VLAN_N_VID) { + if (vid) { if (!pv || !test_bit(vid, pv->vlan_bitmap)) { pr_info("bridge: RTM_NEWNEIGH with unconfigured " "vlan %d on port %s\n", vid, dev->name); @@ -903,27 +887,12 @@ static int __br_fdb_delete(struct net_bridge_port *p, /* Remove neighbor entry with RTM_DELNEIGH */ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr) + const unsigned char *addr, u16 vid) { struct net_bridge_port *p; int err; struct net_port_vlans *pv; - unsigned short vid = VLAN_N_VID; - - if (tb[NDA_VLAN]) { - if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) { - pr_info("bridge: RTM_NEWNEIGH with invalid vlan\n"); - return -EINVAL; - } - vid = nla_get_u16(tb[NDA_VLAN]); - - if (!vid || vid >= VLAN_VID_MASK) { - pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", - vid); - return -EINVAL; - } - } p = br_port_get_rtnl(dev); if (p == NULL) { pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n", @@ -932,7 +901,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], } pv = nbp_get_vlan_info(p); - if (vid != VLAN_N_VID) { + if (vid) { if (!pv || !test_bit(vid, pv->vlan_bitmap)) { pr_info("bridge: RTM_DELNEIGH with unconfigured " "vlan %d on port %s\n", vid, dev->name); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 5b370773ad9c..1b529da8234d 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -404,9 +404,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, const unsigned char *addr, u16 vid, bool added_by_user); int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, const unsigned char *addr); + struct net_device *dev, const unsigned char *addr, u16 vid); int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 nlh_flags); + const unsigned char *addr, u16 vid, u16 nlh_flags); int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, struct net_device *fdev, int idx); int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b9b7dfaf202b..1a233c1c8ab4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -2312,7 +2313,7 @@ errout: int ndo_dflt_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, + const unsigned char *addr, u16 vid, u16 flags) { int err = -EINVAL; @@ -2338,6 +2339,28 @@ int ndo_dflt_fdb_add(struct ndmsg *ndm, } EXPORT_SYMBOL(ndo_dflt_fdb_add); +static int fdb_vid_parse(struct nlattr *vlan_attr, u16 *p_vid) +{ + u16 vid = 0; + + if (vlan_attr) { + if (nla_len(vlan_attr) != sizeof(u16)) { + pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan\n"); + return -EINVAL; + } + + vid = nla_get_u16(vlan_attr); + + if (!vid || vid >= VLAN_VID_MASK) { + pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan id %d\n", + vid); + return -EINVAL; + } + } + *p_vid = vid; + return 0; +} + static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) { struct net *net = sock_net(skb->sk); @@ -2345,6 +2368,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) struct nlattr *tb[NDA_MAX+1]; struct net_device *dev; u8 *addr; + u16 vid; int err; err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); @@ -2370,6 +2394,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) addr = nla_data(tb[NDA_LLADDR]); + err = fdb_vid_parse(tb[NDA_VLAN], &vid); + if (err) + return err; + err = -EOPNOTSUPP; /* Support fdb on master device the net/bridge default case */ @@ -2378,7 +2406,8 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) struct net_device *br_dev = netdev_master_upper_dev_get(dev); const struct net_device_ops *ops = br_dev->netdev_ops; - err = ops->ndo_fdb_add(ndm, tb, dev, addr, nlh->nlmsg_flags); + err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid, + nlh->nlmsg_flags); if (err) goto out; else @@ -2389,9 +2418,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) if ((ndm->ndm_flags & NTF_SELF)) { if (dev->netdev_ops->ndo_fdb_add) err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, + vid, nlh->nlmsg_flags); else - err = ndo_dflt_fdb_add(ndm, tb, dev, addr, + err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, nlh->nlmsg_flags); if (!err) { @@ -2409,7 +2439,7 @@ out: int ndo_dflt_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr) + const unsigned char *addr, u16 vid) { int err = -EINVAL; @@ -2438,6 +2468,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) struct net_device *dev; int err = -EINVAL; __u8 *addr; + u16 vid; if (!netlink_capable(skb, CAP_NET_ADMIN)) return -EPERM; @@ -2465,6 +2496,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) addr = nla_data(tb[NDA_LLADDR]); + err = fdb_vid_parse(tb[NDA_VLAN], &vid); + if (err) + return err; + err = -EOPNOTSUPP; /* Support fdb on master device the net/bridge default case */ @@ -2474,7 +2509,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) const struct net_device_ops *ops = br_dev->netdev_ops; if (ops->ndo_fdb_del) - err = ops->ndo_fdb_del(ndm, tb, dev, addr); + err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid); if (err) goto out; @@ -2485,9 +2520,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) /* Embedded bridge, macvlan, and any other device support */ if (ndm->ndm_flags & NTF_SELF) { if (dev->netdev_ops->ndo_fdb_del) - err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); + err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr, + vid); else - err = ndo_dflt_fdb_del(ndm, tb, dev, addr); + err = ndo_dflt_fdb_del(ndm, tb, dev, addr, vid); if (!err) { rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); -- cgit v1.2.3 From 02637fce3e0103ba086b9c33b6d529e69460e4b6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:16 +0100 Subject: net: rename netdev_phys_port_id to more generic name So this can be reused for identification of other "items" as well. Signed-off-by: Jiri Pirko Reviewed-by: Thomas Graf Acked-by: John Fastabend Acked-by: Andy Gospodarek Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 2 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 2 +- include/linux/netdevice.h | 16 ++++++++-------- net/core/dev.c | 2 +- net/core/net-sysfs.c | 2 +- net/core/rtnetlink.c | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c4bd025c74c9..336ef3cf5773 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12537,7 +12537,7 @@ static int bnx2x_validate_addr(struct net_device *dev) } static int bnx2x_get_phys_port_id(struct net_device *netdev, - struct netdev_phys_port_id *ppid) + struct netdev_phys_item_id *ppid) { struct bnx2x *bp = netdev_priv(netdev); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5ed5e4036dd9..9ae4270db0b3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7511,7 +7511,7 @@ static void i40e_del_vxlan_port(struct net_device *netdev, #endif static int i40e_get_phys_port_id(struct net_device *netdev, - struct netdev_phys_port_id *ppid) + struct netdev_phys_item_id *ppid) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_pf *pf = np->vsi->back; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index b7c99780aef3..1597fb07576c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2259,7 +2259,7 @@ static int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_st #define PORT_ID_BYTE_LEN 8 static int mlx4_en_get_phys_port_id(struct net_device *dev, - struct netdev_phys_port_id *ppid) + struct netdev_phys_item_id *ppid) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_dev *mdev = priv->mdev->dev; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 3227c8063edd..1aa25b13ace1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -461,7 +461,7 @@ static void qlcnic_82xx_cancel_idc_work(struct qlcnic_adapter *adapter) } static int qlcnic_get_phys_port_id(struct net_device *netdev, - struct netdev_phys_port_id *ppid) + struct netdev_phys_item_id *ppid) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_hardware_context *ahw = adapter->ahw; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 589929cf4700..4bd41d72559d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -754,13 +754,13 @@ struct netdev_fcoe_hbainfo { }; #endif -#define MAX_PHYS_PORT_ID_LEN 32 +#define MAX_PHYS_ITEM_ID_LEN 32 -/* This structure holds a unique identifier to identify the - * physical port used by a netdevice. +/* This structure holds a unique identifier to identify some + * physical item (port for example) used by a netdevice. */ -struct netdev_phys_port_id { - unsigned char id[MAX_PHYS_PORT_ID_LEN]; +struct netdev_phys_item_id { + unsigned char id[MAX_PHYS_ITEM_ID_LEN]; unsigned char id_len; }; @@ -976,7 +976,7 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * USB_CDC_NOTIFY_NETWORK_CONNECTION) should NOT implement this function. * * int (*ndo_get_phys_port_id)(struct net_device *dev, - * struct netdev_phys_port_id *ppid); + * struct netdev_phys_item_id *ppid); * Called to get ID of physical port of this device. If driver does * not implement this, it is assumed that the hw is not able to have * multiple net devices on single physical port. @@ -1152,7 +1152,7 @@ struct net_device_ops { int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); int (*ndo_get_phys_port_id)(struct net_device *dev, - struct netdev_phys_port_id *ppid); + struct netdev_phys_item_id *ppid); void (*ndo_add_vxlan_port)(struct net_device *dev, sa_family_t sa_family, __be16 port); @@ -2870,7 +2870,7 @@ void dev_set_group(struct net_device *, int); int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_change_carrier(struct net_device *, bool new_carrier); int dev_get_phys_port_id(struct net_device *dev, - struct netdev_phys_port_id *ppid); + struct netdev_phys_item_id *ppid); struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev); struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); diff --git a/net/core/dev.c b/net/core/dev.c index ac4836241a96..0814a560e5f3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5846,7 +5846,7 @@ EXPORT_SYMBOL(dev_change_carrier); * Get device physical port ID */ int dev_get_phys_port_id(struct net_device *dev, - struct netdev_phys_port_id *ppid) + struct netdev_phys_item_id *ppid) { const struct net_device_ops *ops = dev->netdev_ops; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 1a24602cd54e..26c46f4726c5 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -404,7 +404,7 @@ static ssize_t phys_port_id_show(struct device *dev, return restart_syscall(); if (dev_isalive(netdev)) { - struct netdev_phys_port_id ppid; + struct netdev_phys_item_id ppid; ret = dev_get_phys_port_id(netdev, &ppid); if (!ret) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1a233c1c8ab4..0640f1fbe9dd 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -869,7 +869,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */ - + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */ + + nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_PORT_ID */ } static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) @@ -953,7 +953,7 @@ static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev, static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev) { int err; - struct netdev_phys_port_id ppid; + struct netdev_phys_item_id ppid; err = dev_get_phys_port_id(dev, &ppid); if (err) { @@ -1197,7 +1197,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_PROMISCUITY] = { .type = NLA_U32 }, [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 }, [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, - [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, + [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */ }; -- cgit v1.2.3 From 007f790c8276271de26416f90d55561bcc96588a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:17 +0100 Subject: net: introduce generic switch devices support The goal of this is to provide a possibility to support various switch chips. Drivers should implement relevant ndos to do so. Now there is only one ndo defined: - for getting physical switch id is in place. Note that user can use random port netdevice to access the switch. Signed-off-by: Jiri Pirko Reviewed-by: Thomas Graf Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 59 ++++++++++++++++++++++++++++++++++ MAINTAINERS | 7 ++++ include/linux/netdevice.h | 10 ++++++ include/net/switchdev.h | 30 +++++++++++++++++ net/Kconfig | 1 + net/Makefile | 3 ++ net/switchdev/Kconfig | 13 ++++++++ net/switchdev/Makefile | 5 +++ net/switchdev/switchdev.c | 33 +++++++++++++++++++ 9 files changed, 161 insertions(+) create mode 100644 Documentation/networking/switchdev.txt create mode 100644 include/net/switchdev.h create mode 100644 net/switchdev/Kconfig create mode 100644 net/switchdev/Makefile create mode 100644 net/switchdev/switchdev.c (limited to 'include') diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt new file mode 100644 index 000000000000..f981a9295a39 --- /dev/null +++ b/Documentation/networking/switchdev.txt @@ -0,0 +1,59 @@ +Switch (and switch-ish) device drivers HOWTO +=========================== + +Please note that the word "switch" is here used in very generic meaning. +This include devices supporting L2/L3 but also various flow offloading chips, +including switches embedded into SR-IOV NICs. + +Lets describe a topology a bit. Imagine the following example: + + +----------------------------+ +---------------+ + | SOME switch chip | | CPU | + +----------------------------+ +---------------+ + port1 port2 port3 port4 MNGMNT | PCI-E | + | | | | | +---------------+ + PHY PHY | | | | NIC0 NIC1 + | | | | | | + | | +- PCI-E -+ | | + | +------- MII -------+ | + +------------- MII ------------+ + +In this example, there are two independent lines between the switch silicon +and CPU. NIC0 and NIC1 drivers are not aware of a switch presence. They are +separate from the switch driver. SOME switch chip is by managed by a driver +via PCI-E device MNGMNT. Note that MNGMNT device, NIC0 and NIC1 may be +connected to some other type of bus. + +Now, for the previous example show the representation in kernel: + + +----------------------------+ +---------------+ + | SOME switch chip | | CPU | + +----------------------------+ +---------------+ + sw0p0 sw0p1 sw0p2 sw0p3 MNGMNT | PCI-E | + | | | | | +---------------+ + PHY PHY | | | | eth0 eth1 + | | | | | | + | | +- PCI-E -+ | | + | +------- MII -------+ | + +------------- MII ------------+ + +Lets call the example switch driver for SOME switch chip "SOMEswitch". This +driver takes care of PCI-E device MNGMNT. There is a netdevice instance sw0pX +created for each port of a switch. These netdevices are instances +of "SOMEswitch" driver. sw0pX netdevices serve as a "representation" +of the switch chip. eth0 and eth1 are instances of some other existing driver. + +The only difference of the switch-port netdevice from the ordinary netdevice +is that is implements couple more NDOs: + + ndo_switch_parent_id_get - This returns the same ID for two port netdevices + of the same physical switch chip. This is + mandatory to be implemented by all switch drivers + and serves the caller for recognition of a port + netdevice. + ndo_switch_parent_* - Functions that serve for a manipulation of the switch + chip itself (it can be though of as a "parent" of the + port, therefore the name). They are not port-specific. + Caller might use arbitrary port netdevice of the same + switch and it will make no difference. + ndo_switch_port_* - Functions that serve for a port-specific manipulation. diff --git a/MAINTAINERS b/MAINTAINERS index 6b880deae3d2..3aba0ac2d5a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9059,6 +9059,13 @@ F: lib/swiotlb.c F: arch/*/kernel/pci-swiotlb.c F: include/linux/swiotlb.h +SWITCHDEV +M: Jiri Pirko +L: netdev@vger.kernel.org +S: Supported +F: net/switchdev/ +F: include/net/switchdev.h + SYNOPSYS ARC ARCHITECTURE M: Vineet Gupta S: Supported diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4bd41d72559d..3603f31e78f3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1018,6 +1018,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * performing GSO on a packet. The device returns true if it is * able to GSO the packet, false otherwise. If the return value is * false the stack will do software GSO. + * + * int (*ndo_switch_parent_id_get)(struct net_device *dev, + * struct netdev_phys_item_id *psid); + * Called to get an ID of the switch chip this port is part of. + * If driver implements this, it indicates that it represents a port + * of a switch chip. */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1171,6 +1177,10 @@ struct net_device_ops { int (*ndo_get_lock_subclass)(struct net_device *dev); bool (*ndo_gso_check) (struct sk_buff *skb, struct net_device *dev); +#ifdef CONFIG_NET_SWITCHDEV + int (*ndo_switch_parent_id_get)(struct net_device *dev, + struct netdev_phys_item_id *psid); +#endif }; /** diff --git a/include/net/switchdev.h b/include/net/switchdev.h new file mode 100644 index 000000000000..7a52360a1446 --- /dev/null +++ b/include/net/switchdev.h @@ -0,0 +1,30 @@ +/* + * include/net/switchdev.h - Switch device API + * Copyright (c) 2014 Jiri Pirko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef _LINUX_SWITCHDEV_H_ +#define _LINUX_SWITCHDEV_H_ + +#include + +#ifdef CONFIG_NET_SWITCHDEV + +int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid); + +#else + +static inline int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) +{ + return -EOPNOTSUPP; +} + +#endif + +#endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 99815b5454bf..ff9ffc17fa0e 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -228,6 +228,7 @@ source "net/vmw_vsock/Kconfig" source "net/netlink/Kconfig" source "net/mpls/Kconfig" source "net/hsr/Kconfig" +source "net/switchdev/Kconfig" config RPS boolean diff --git a/net/Makefile b/net/Makefile index 7ed1970074b0..95fc694e4ddc 100644 --- a/net/Makefile +++ b/net/Makefile @@ -73,3 +73,6 @@ obj-$(CONFIG_OPENVSWITCH) += openvswitch/ obj-$(CONFIG_VSOCKETS) += vmw_vsock/ obj-$(CONFIG_NET_MPLS_GSO) += mpls/ obj-$(CONFIG_HSR) += hsr/ +ifneq ($(CONFIG_NET_SWITCHDEV),) +obj-y += switchdev/ +endif diff --git a/net/switchdev/Kconfig b/net/switchdev/Kconfig new file mode 100644 index 000000000000..155754588fd6 --- /dev/null +++ b/net/switchdev/Kconfig @@ -0,0 +1,13 @@ +# +# Configuration for Switch device support +# + +config NET_SWITCHDEV + boolean "Switch (and switch-ish) device support (EXPERIMENTAL)" + depends on INET + ---help--- + This module provides glue between core networking code and device + drivers in order to support hardware switch chips in very generic + meaning of the word "switch". This include devices supporting L2/L3 but + also various flow offloading chips, including switches embedded into + SR-IOV NICs. diff --git a/net/switchdev/Makefile b/net/switchdev/Makefile new file mode 100644 index 000000000000..5ed63ed324d0 --- /dev/null +++ b/net/switchdev/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Switch device API +# + +obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c new file mode 100644 index 000000000000..66973deaae56 --- /dev/null +++ b/net/switchdev/switchdev.c @@ -0,0 +1,33 @@ +/* + * net/switchdev/switchdev.c - Switch device API + * Copyright (c) 2014 Jiri Pirko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/** + * netdev_switch_parent_id_get - Get ID of a switch + * @dev: port device + * @psid: switch ID + * + * Get ID of a switch this port is part of. + */ +int netdev_switch_parent_id_get(struct net_device *dev, + struct netdev_phys_item_id *psid) +{ + const struct net_device_ops *ops = dev->netdev_ops; + + if (!ops->ndo_switch_parent_id_get) + return -EOPNOTSUPP; + return ops->ndo_switch_parent_id_get(dev, psid); +} +EXPORT_SYMBOL(netdev_switch_parent_id_get); -- cgit v1.2.3 From 82f2841291cfaf4d225aa1766424280254d3e3b2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 28 Nov 2014 14:34:18 +0100 Subject: rtnl: expose physical switch id for particular device The netdevice represents a port in a switch, it will expose IFLA_PHYS_SWITCH_ID value via rtnl. Two netdevices with the same value belong to one physical switch. Signed-off-by: Jiri Pirko Reviewed-by: Thomas Graf Acked-by: John Fastabend Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + net/core/rtnetlink.c | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 36bddc233633..623f1a7c7627 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -145,6 +145,7 @@ enum { IFLA_CARRIER, IFLA_PHYS_PORT_ID, IFLA_CARRIER_CHANGES, + IFLA_PHYS_SWITCH_ID, __IFLA_MAX }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 0640f1fbe9dd..aa5cd2c53a56 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -869,7 +870,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */ - + nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_PORT_ID */ + + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */ + + nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_SWITCH_ID */ } static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) @@ -968,6 +970,24 @@ static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev) return 0; } +static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) +{ + int err; + struct netdev_phys_item_id psid; + + err = netdev_switch_parent_id_get(dev, &psid); + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + + if (nla_put(skb, IFLA_PHYS_SWITCH_ID, psid.id_len, psid.id)) + return -EMSGSIZE; + + return 0; +} + static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, int type, u32 pid, u32 seq, u32 change, unsigned int flags, u32 ext_filter_mask) @@ -1040,6 +1060,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (rtnl_phys_port_id_fill(skb, dev)) goto nla_put_failure; + if (rtnl_phys_switch_id_fill(skb, dev)) + goto nla_put_failure; + attr = nla_reserve(skb, IFLA_STATS, sizeof(struct rtnl_link_stats)); if (attr == NULL) @@ -1199,6 +1222,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */ + [IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { -- cgit v1.2.3 From 38dcf357aed299186ecb090cc2f5290cc17d637d Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:20 +0100 Subject: bridge: call netdev_sw_port_stp_update when bridge port STP status changes To notify switch driver of change in STP state of bridge port, add new .ndo op and provide switchdev wrapper func to call ndo op. Use it in bridge code then. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: Andy Gospodarek Acked-by: Thomas Graf Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- include/linux/netdevice.h | 5 +++++ include/net/switchdev.h | 7 +++++++ net/bridge/br_stp.c | 7 +++++++ net/switchdev/switchdev.c | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3603f31e78f3..29c92ee9ed56 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1024,6 +1024,9 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * Called to get an ID of the switch chip this port is part of. * If driver implements this, it indicates that it represents a port * of a switch chip. + * int (*ndo_switch_port_stp_update)(struct net_device *dev, u8 state); + * Called to notify switch device port of bridge port STP + * state change. */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1180,6 +1183,8 @@ struct net_device_ops { #ifdef CONFIG_NET_SWITCHDEV int (*ndo_switch_parent_id_get)(struct net_device *dev, struct netdev_phys_item_id *psid); + int (*ndo_switch_port_stp_update)(struct net_device *dev, + u8 state); #endif }; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 7a52360a1446..8a6d1641fd9b 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -16,6 +16,7 @@ int netdev_switch_parent_id_get(struct net_device *dev, struct netdev_phys_item_id *psid); +int netdev_switch_port_stp_update(struct net_device *dev, u8 state); #else @@ -25,6 +26,12 @@ static inline int netdev_switch_parent_id_get(struct net_device *dev, return -EOPNOTSUPP; } +static inline int netdev_switch_port_stp_update(struct net_device *dev, + u8 state) +{ + return -EOPNOTSUPP; +} + #endif #endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 2b047bcf42a4..fb3ebe615513 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -12,6 +12,7 @@ */ #include #include +#include #include "br_private.h" #include "br_private_stp.h" @@ -38,7 +39,13 @@ void br_log_state(const struct net_bridge_port *p) void br_set_state(struct net_bridge_port *p, unsigned int state) { + int err; + p->state = state; + err = netdev_switch_port_stp_update(p->dev, state); + if (err && err != -EOPNOTSUPP) + br_warn(p->br, "error setting offload STP state on port %u(%s)\n", + (unsigned int) p->port_no, p->dev->name); } /* called under bridge lock */ diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 66973deaae56..d162b21b14bd 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -31,3 +31,22 @@ int netdev_switch_parent_id_get(struct net_device *dev, return ops->ndo_switch_parent_id_get(dev, psid); } EXPORT_SYMBOL(netdev_switch_parent_id_get); + +/** + * netdev_switch_port_stp_update - Notify switch device port of STP + * state change + * @dev: port device + * @state: port STP state + * + * Notify switch device port of bridge port STP state change. + */ +int netdev_switch_port_stp_update(struct net_device *dev, u8 state) +{ + const struct net_device_ops *ops = dev->netdev_ops; + + if (!ops->ndo_switch_port_stp_update) + return -EOPNOTSUPP; + WARN_ON(!ops->ndo_switch_parent_id_get); + return ops->ndo_switch_port_stp_update(dev, state); +} +EXPORT_SYMBOL(netdev_switch_port_stp_update); -- cgit v1.2.3 From cf6b8e1eedffd9ef9a22c0c9453d752b07daf89a Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:21 +0100 Subject: bridge: add API to notify bridge driver of learned FBD on offloaded device When the swdev device learns a new mac/vlan on a port, it sends some async notification to the driver and the driver installs an FDB in the device. To give a holistic system view, the learned mac/vlan should be reflected in the bridge's FBD table, so the user, using normal iproute2 cmds, can view what is currently learned by the device. This API on the bridge driver gives a way for the swdev driver to install an FBD entry in the bridge FBD table. (And remove one). This is equivalent to the device running these cmds: bridge fdb [add|del] dev vid master This patch needs some extra eyeballs for review, in paricular around the locking and contexts. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/if_bridge.h | 18 +++++++++ include/uapi/linux/neighbour.h | 1 + net/bridge/br_fdb.c | 91 +++++++++++++++++++++++++++++++++++++++++- net/bridge/br_private.h | 3 +- 4 files changed, 111 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 808dcb8cc04f..fa2eca625129 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -37,6 +37,24 @@ extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __use typedef int br_should_route_hook_t(struct sk_buff *skb); extern br_should_route_hook_t __rcu *br_should_route_hook; +#if IS_ENABLED(CONFIG_BRIDGE) +int br_fdb_external_learn_add(struct net_device *dev, + const unsigned char *addr, u16 vid); +int br_fdb_external_learn_del(struct net_device *dev, + const unsigned char *addr, u16 vid); +#else +static inline int br_fdb_external_learn_add(struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + return 0; +} +static inline int br_fdb_external_learn_del(struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + return 0; +} +#endif + #if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) int br_multicast_list_adjacent(struct net_device *dev, struct list_head *br_ip_list); diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index 2f043af7fcd6..f3d77f9f1e0b 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -38,6 +38,7 @@ enum { #define NTF_SELF 0x02 #define NTF_MASTER 0x04 #define NTF_PROXY 0x08 /* == ATF_PUBL */ +#define NTF_EXT_LEARNED 0x10 #define NTF_ROUTER 0x80 /* diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index b1be971eb06c..cc36e59db7d7 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -481,6 +481,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb->is_local = 0; fdb->is_static = 0; fdb->added_by_user = 0; + fdb->added_by_external_learn = 0; fdb->updated = fdb->used = jiffies; hlist_add_head_rcu(&fdb->hlist, head); } @@ -613,7 +614,7 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, ndm->ndm_family = AF_BRIDGE; ndm->ndm_pad1 = 0; ndm->ndm_pad2 = 0; - ndm->ndm_flags = 0; + ndm->ndm_flags = fdb->added_by_external_learn ? NTF_EXT_LEARNED : 0; ndm->ndm_type = 0; ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex; ndm->ndm_state = fdb_to_nud(fdb); @@ -983,3 +984,91 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p) } } } + +int br_fdb_external_learn_add(struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + struct net_bridge_port *p; + struct net_bridge *br; + struct hlist_head *head; + struct net_bridge_fdb_entry *fdb; + int err = 0; + + rtnl_lock(); + + p = br_port_get_rtnl(dev); + if (!p) { + pr_info("bridge: %s not a bridge port\n", dev->name); + err = -EINVAL; + goto err_rtnl_unlock; + } + + br = p->br; + + spin_lock_bh(&br->hash_lock); + + head = &br->hash[br_mac_hash(addr, vid)]; + fdb = fdb_find(head, addr, vid); + if (!fdb) { + fdb = fdb_create(head, p, addr, vid); + if (!fdb) { + err = -ENOMEM; + goto err_unlock; + } + fdb->added_by_external_learn = 1; + fdb_notify(br, fdb, RTM_NEWNEIGH); + } else if (fdb->added_by_external_learn) { + /* Refresh entry */ + fdb->updated = fdb->used = jiffies; + } else if (!fdb->added_by_user) { + /* Take over SW learned entry */ + fdb->added_by_external_learn = 1; + fdb->updated = jiffies; + fdb_notify(br, fdb, RTM_NEWNEIGH); + } + +err_unlock: + spin_unlock_bh(&br->hash_lock); +err_rtnl_unlock: + rtnl_unlock(); + + return err; +} +EXPORT_SYMBOL(br_fdb_external_learn_add); + +int br_fdb_external_learn_del(struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + struct net_bridge_port *p; + struct net_bridge *br; + struct hlist_head *head; + struct net_bridge_fdb_entry *fdb; + int err = 0; + + rtnl_lock(); + + p = br_port_get_rtnl(dev); + if (!p) { + pr_info("bridge: %s not a bridge port\n", dev->name); + err = -EINVAL; + goto err_rtnl_unlock; + } + + br = p->br; + + spin_lock_bh(&br->hash_lock); + + head = &br->hash[br_mac_hash(addr, vid)]; + fdb = fdb_find(head, addr, vid); + if (fdb && fdb->added_by_external_learn) + fdb_delete(br, fdb); + else + err = -ENOENT; + + spin_unlock_bh(&br->hash_lock); +err_rtnl_unlock: + rtnl_unlock(); + + return err; +} +EXPORT_SYMBOL(br_fdb_external_learn_del); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 1b529da8234d..cc36fb3efbdd 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -100,7 +100,8 @@ struct net_bridge_fdb_entry mac_addr addr; unsigned char is_local:1, is_static:1, - added_by_user:1; + added_by_user:1, + added_by_external_learn:1; __u16 vlan_id; }; -- cgit v1.2.3 From 065c212a9e25172069f368b36228379521dadb65 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:22 +0100 Subject: bridge: move private brport flags to if_bridge.h so port drivers can use flags Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Jamal Hadi Salim Acked-by: Andy Gospodarek Acked-by: Florian Fainelli --- include/linux/if_bridge.h | 12 ++++++++++++ net/bridge/br_private.h | 10 ---------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index fa2eca625129..2c81a8efd24d 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -15,6 +15,7 @@ #include #include +#include struct br_ip { union { @@ -32,6 +33,17 @@ struct br_ip_list { struct br_ip addr; }; +#define BR_HAIRPIN_MODE BIT(0) +#define BR_BPDU_GUARD BIT(1) +#define BR_ROOT_BLOCK BIT(2) +#define BR_MULTICAST_FAST_LEAVE BIT(3) +#define BR_ADMIN_COST BIT(4) +#define BR_LEARNING BIT(5) +#define BR_FLOOD BIT(6) +#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) +#define BR_PROMISC BIT(7) +#define BR_PROXYARP BIT(8) + extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); typedef int br_should_route_hook_t(struct sk_buff *skb); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index cc36fb3efbdd..aea3d1339b3f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -164,16 +164,6 @@ struct net_bridge_port struct rcu_head rcu; unsigned long flags; -#define BR_HAIRPIN_MODE 0x00000001 -#define BR_BPDU_GUARD 0x00000002 -#define BR_ROOT_BLOCK 0x00000004 -#define BR_MULTICAST_FAST_LEAVE 0x00000008 -#define BR_ADMIN_COST 0x00000010 -#define BR_LEARNING 0x00000020 -#define BR_FLOOD 0x00000040 -#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) -#define BR_PROMISC 0x00000080 -#define BR_PROXYARP 0x00000100 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING struct bridge_mcast_own_query ip4_own_query; -- cgit v1.2.3 From efacacdaf7cb5a0592ed772e3731636b2742e34a Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:23 +0100 Subject: bridge: add new brport flag LEARNING_SYNC This policy flag controls syncing of learned FDB entries to bridge's FDB. If on, FDB entries learned on bridge port device will be synced. If off, device may still learn new FDB entries but they will not be synced with bridge's FDB. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Roopa Prabhu Acked-by: Jamal Hadi Salim Acked-by: Andy Gospodarek Signed-off-by: David S. Miller --- include/linux/if_bridge.h | 1 + include/uapi/linux/if_link.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 2c81a8efd24d..0a8ce762a47f 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -43,6 +43,7 @@ struct br_ip_list { #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) #define BR_PROMISC BIT(7) #define BR_PROXYARP BIT(8) +#define BR_LEARNING_SYNC BIT(9) extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 623f1a7c7627..f7d0d2d7173a 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -245,6 +245,7 @@ enum { IFLA_BRPORT_LEARNING, /* mac learning */ IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ IFLA_BRPORT_PROXYARP, /* proxy ARP */ + IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */ __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -- cgit v1.2.3 From 345cd494a324c149ef7293f4bedf2d7131a6de7c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:24 +0100 Subject: bridge: add new hwmode swdev Current hwmode settings are "vepa" or "veb". These are for NIC interfaces with basic bridging function offloaded to HW. Add new "swdev" for full switch device offloads. Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/uapi/linux/if_bridge.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index da17e456908d..296a556454e3 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -105,6 +105,7 @@ struct __fdb_entry { #define BRIDGE_MODE_VEB 0 /* Default loopback mode */ #define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */ +#define BRIDGE_MODE_SWDEV 2 /* Full switch device offload */ /* Bridge management nested attributes * [IFLA_AF_SPEC] = { -- cgit v1.2.3 From 2c3c031c8f8930861815fa1685d7c5e8ccec047c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Fri, 28 Nov 2014 14:34:25 +0100 Subject: bridge: add brport flags to dflt bridge_getlink To allow brport device to return current brport flags set on port. Add returned flags to nested IFLA_PROTINFO netlink msg built in dflt getlink. With this change, netlink msg returned for bridge_getlink contains the port's offloaded flag settings (the port's SELF settings). Signed-off-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Andy Gospodarek Acked-by: Thomas Graf Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 3 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- include/linux/rtnetlink.h | 3 ++- net/core/rtnetlink.c | 39 ++++++++++++++++++++++++++- 4 files changed, 43 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index dc77ec2bdafd..e0ab7673afe7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4367,7 +4367,8 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return ndo_dflt_bridge_getlink(skb, pid, seq, dev, hsw_mode == PORT_FWD_TYPE_VEPA ? - BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB); + BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB, + 0, 0); } #ifdef CONFIG_BE2NET_VXLAN diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 74aadeb56ada..9afa167d52a6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7778,7 +7778,7 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, else mode = BRIDGE_MODE_VEPA; - return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode); + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0); } static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 063f0f581fe0..3b0419072f88 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -103,5 +103,6 @@ extern int ndo_dflt_fdb_del(struct ndmsg *ndm, u16 vid); extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u16 mode); + struct net_device *dev, u16 mode, + u32 flags, u32 mask); #endif /* __LINUX_RTNETLINK_H */ diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index aa5cd2c53a56..61cb7e7cc3c7 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2687,12 +2687,22 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask, + unsigned int attrnum, unsigned int flag) +{ + if (mask & flag) + return nla_put_u8(skb, attrnum, !!(flags & flag)); + return 0; +} + int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u16 mode) + struct net_device *dev, u16 mode, + u32 flags, u32 mask) { struct nlmsghdr *nlh; struct ifinfomsg *ifm; struct nlattr *br_afspec; + struct nlattr *protinfo; u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; struct net_device *br_dev = netdev_master_upper_dev_get(dev); @@ -2731,6 +2741,33 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, } nla_nest_end(skb, br_afspec); + protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); + if (!protinfo) + goto nla_put_failure; + + if (brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_MODE, BR_HAIRPIN_MODE) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_GUARD, BR_BPDU_GUARD) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_FAST_LEAVE, + BR_MULTICAST_FAST_LEAVE) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_LEARNING, BR_LEARNING) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_LEARNING_SYNC, BR_LEARNING_SYNC) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_PROXYARP, BR_PROXYARP)) { + nla_nest_cancel(skb, protinfo); + goto nla_put_failure; + } + + nla_nest_end(skb, protinfo); + return nlmsg_end(skb, nlh); nla_put_failure: nlmsg_cancel(skb, nlh); -- cgit v1.2.3