Skip to contentSkip to conversation

introduce rocker switch driver with hardware accelerated datapath api - phase 1: bridge fdb offload

PATCH Superseded Jiri Pirko 14 participants 100 messages Nov 9, 2014 – Nov 27, 2014

Subsystems (11)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Jiri Pirko

author maintainer
#0 lore raw

v2 cover introduce rocker switch driver with hardware accelerated datapath api - phase 1: bridge fdb offload

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

So what this patchset includes:
- introduce switchdev api for implementing switch drivers (so far only linux bridge fdb offload is covered)
- introduce rocker switch driver which implements switchdev api

As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied.

For detailed description, please see individual patches.

v1->v2:
- addressed all DaveM's comments

Jiri Pirko (5):
net: rename netdev_phys_port_id to more generic name
net: introduce generic switch devices support
rtnl: expose physical switch id for particular device
net-sysfs: expose physical switch id for particular device
rocker: introduce rocker switch driver

Scott Feldman (5):
bridge: introduce fdb offloading via switchdev
bridge: call netdev_sw_port_stp_update when bridge port STP status
changes
bridge: add API to notify bridge driver of learned FBD on offloaded
device
rocker: implement rocker ofdpa flow table manipulation
rocker: implement L2 bridge offloading

 Documentation/networking/switchdev.txt           |   59 +
 MAINTAINERS                                      |   14 +
 drivers/net/ethernet/Kconfig                     |    1 +
 drivers/net/ethernet/Makefile                    |    1 +
 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 +-
 drivers/net/ethernet/rocker/Kconfig              |   27 +
 drivers/net/ethernet/rocker/Makefile             |    5 +
 drivers/net/ethernet/rocker/rocker.c             | 4182 ++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h             |  427 +++
 include/linux/if_bridge.h                        |   18 +
 include/linux/netdevice.h                        |   48 +-
 include/net/switchdev.h                          |   53 +
 include/uapi/linux/if_link.h                     |    1 +
 net/Kconfig                                      |    1 +
 net/Makefile                                     |    3 +
 net/bridge/br_fdb.c                              |   94 +-
 net/bridge/br_netlink.c                          |    2 +
 net/bridge/br_stp.c                              |    4 +
 net/bridge/br_stp_if.c                           |    3 +
 net/bridge/br_stp_timer.c                        |    2 +
 net/core/dev.c                                   |    2 +-
 net/core/net-sysfs.c                             |   26 +-
 net/core/rtnetlink.c                             |   30 +-
 net/switchdev/Kconfig                            |   13 +
 net/switchdev/Makefile                           |    5 +
 net/switchdev/switchdev.c                        |   93 +
 29 files changed, 5104 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/networking/switchdev.txt
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h
 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
Signature · 1 line
1.9.3
author maintainer
#1 lore raw

PATCH v2 1/10 net: rename netdev_phys_port_id to more generic name

So this can be reused for identification of other "items" as well.

---
 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(-)
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +1 -1
index c4bd025..336ef3c 100644
@@ -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);
 
drivers/net/ethernet/intel/i40e/i40e_main.c +1 -1
index 1a98e23..d749165 100644
@@ -7373,7 +7373,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;
drivers/net/ethernet/mellanox/mlx4/en_netdev.c +1 -1
index 0efbae9..bd007c3 100644
@@ -2258,7 +2258,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;
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +1 -1
index f5e29f7..6e514d2 100644
@@ -460,7 +460,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;
include/linux/netdevice.h +8 -8
index 90ac959..71922e0 100644
@@ -753,13 +753,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;
 };
 
@@ -975,7 +975,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.
@@ -1149,7 +1149,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);
@@ -2878,7 +2878,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);
net/core/dev.c +1 -1
index 70bb609..9c67f36 100644
@@ -5818,7 +5818,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;
 
net/core/net-sysfs.c +1 -1
index 9dd0669..55dc4da 100644
@@ -387,7 +387,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)
net/core/rtnetlink.c +3 -3
index a688268..1087c6d 100644
@@ -868,7 +868,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)
@@ -952,7 +952,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) {
@@ -1196,7 +1196,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 */
 };
 
Signature · 1 line
1.9.3
#2 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 32 lines · Jiri Pirko

So this can be reused for identification of other "items" as well.

net/core/net-sysfs.c +1 -1
index 9dd0669..55dc4da 100644
@@ -387,7 +387,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)
net/core/rtnetlink.c +1 -1
index a688268..1087c6d 100644
@@ -868,7 +868,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 */
  }
 

[...]

Quoted 11 lines

static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)

net/core/rtnetlink.c +1 -1
@@ -952,7 +952,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) {

net/core/rtnetlink.c static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · line 1201

Quoted 7 lines
net/core/rtnetlink.c +1 -1
@@ -1196,7 +1196,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 */
  };

wouldnt this just break an existing ABI? You may need to introduce a new attribute.

cheers,
jamal

maintainer
#3 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

From: Jamal Hadi Salim <[email protected]>
Date: Sun, 09 Nov 2014 22:35:12 -0500

Quoted 2 lines

wouldnt this just break an existing ABI? You may need to introduce a new attribute.

He isn't breaking anything Jamal, he's just changing the internal macro name we use for the attribute's maximum length.

Please read his patches carefully instead of jumping to conclusions.

#4 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 8 lines · David Miller

From: Jamal Hadi Salim <[email protected]>
Date: Sun, 09 Nov 2014 22:35:12 -0500

Quoted 2 lines

wouldnt this just break an existing ABI? You may need to introduce a new attribute.

He isn't breaking anything Jamal, he's just changing the internal macro name we use for the attribute's maximum length.

It is a _user space visible rename_, how about:

#define MAX_PHYS_ITEM_ID_LEN 32
#define MAX_PHYS_PORT_ID_LEN MAX_PHYS_ITEM_ID_LEN

I did miss the fact that the size didnt change.

cheers,
jamal

#5 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 10 lines · Jamal Hadi Salim
Quoted 8 lines · David Miller

From: Jamal Hadi Salim <[email protected]>
Date: Sun, 09 Nov 2014 22:35:12 -0500

Quoted 2 lines

wouldnt this just break an existing ABI? You may need to introduce a new attribute.

He isn't breaking anything Jamal, he's just changing the internal macro name we use for the attribute's maximum length.

Quoted 6 lines

It is a _user space visible rename_, how about:

#define MAX_PHYS_ITEM_ID_LEN 32
#define MAX_PHYS_PORT_ID_LEN MAX_PHYS_ITEM_ID_LEN

I did miss the fact that the size didnt change.

Actually, it's currently not exposed via any uapi header ...

$ git grep -n MAX_PHYS_PORT_ID_LEN
include/linux/netdevice.h:756:#define MAX_PHYS_PORT_ID_LEN 32
include/linux/netdevice.h:762:  unsigned char id[MAX_PHYS_PORT_ID_LEN];
net/core/rtnetlink.c:871:              + nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
net/core/rtnetlink.c:1199:      [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },

... and based on commit 66cae9ed6bc4 ("rtnl: export physical port id via RT netlink") only exported as read-only.

Best,
Daniel

#6 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 11 lines · Daniel Borkmann
$ git grep -n MAX_PHYS_PORT_ID_LEN
include/linux/netdevice.h:756:#define MAX_PHYS_PORT_ID_LEN 32
include/linux/netdevice.h:762:  unsigned char id[MAX_PHYS_PORT_ID_LEN];
net/core/rtnetlink.c:871:              +
nla_total_size(MAX_PHYS_PORT_ID_LEN); /* IFLA_PHYS_PORT_ID */
net/core/rtnetlink.c:1199:      [IFLA_PHYS_PORT_ID]     = { .type =
NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },

... and based on commit 66cae9ed6bc4 ("rtnl: export physical port id via RT netlink") only exported as read-only.

I guess it is *not exported* if no user space code sees it. If that is the case, I agree that my suggestion is unneeded.

cheers,
jamal

maintainer
#7 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

In reply to Jamal Hadi Salim

From: Jamal Hadi Salim <[email protected]>
Date: Mon, 10 Nov 2014 07:06:29 -0500

Quoted 6 lines

It is a _user space visible rename_, how about:

#define MAX_PHYS_ITEM_ID_LEN 32
#define MAX_PHYS_PORT_ID_LEN MAX_PHYS_ITEM_ID_LEN

I did miss the fact that the size didnt change.

The user cannot see this macro Jamal, please really read this code, instead of, once again, jumping to conclusions.

author maintainer
#8 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

In reply to Jamal Hadi Salim
Quoted 44 lines · Mon, Nov 10, 2014 at 04:35:12AM CET, [email protected] wrote:
Quoted 32 lines · Jiri Pirko

So this can be reused for identification of other "items" as well.

net/core/net-sysfs.c +1 -1
index 9dd0669..55dc4da 100644
@@ -387,7 +387,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)
net/core/rtnetlink.c +1 -1
index a688268..1087c6d 100644
@@ -868,7 +868,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 */
 }
 

[...]

Quoted 8 lines

static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)

net/core/rtnetlink.c +1 -1
@@ -952,7 +952,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;
 
Quoted 14 lines

net/core/rtnetlink.c static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · line 1201

Quoted 10 lines
net/core/rtnetlink.c +1 -1
 	err = dev_get_phys_port_id(dev, &ppid);
 	if (err) {
@@ -1196,7 +1196,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 */
 };

wouldnt this just break an existing ABI? You may need to introduce a new attribute.

I don't see a reason why this would break kabi:

-#define MAX_PHYS_PORT_ID_LEN 32
+#define MAX_PHYS_ITEM_ID_LEN 32

Quoted 5 lines

cheers,
jamal

#9 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

include/linux/netdevice.h struct netdev_fcoe_hbainfo { · line 756

Quoted 7 lines · Jiri Pirko

Mon, Nov 10, 2014 at 04:35:12AM CET, [email protected] wrote:

I don't see a reason why this would break kabi:

include/linux/netdevice.h +1 -1
-#define MAX_PHYS_PORT_ID_LEN 32
+#define MAX_PHYS_ITEM_ID_LEN 32

refer to my response to Dave. Just define MAX_PHYS_PORT_ID_LEN to MAX_PHYS_ITEM_ID_LEN so people dont have to change their code because a name change.

cheers,
jamal

author maintainer
#10 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 5 lines · Mon, Nov 10, 2014 at 01:17:04PM CET, [email protected] wrote:
Quoted 4 lines · Jiri Pirko

Mon, Nov 10, 2014 at 04:35:12AM CET, [email protected] wrote:

I don't see a reason why this would break kabi:

Quoted 7 lines

include/linux/netdevice.h struct netdev_fcoe_hbainfo { · line 756

Quoted 3 lines
include/linux/netdevice.h +1 -1
-#define MAX_PHYS_PORT_ID_LEN 32
+#define MAX_PHYS_ITEM_ID_LEN 32

refer to my response to Dave. Just define MAX_PHYS_PORT_ID_LEN to MAX_PHYS_ITEM_ID_LEN so people dont have to change their code because a name change.

Jamal, please look at the patch & code. MAX_PHYS_PORT_ID_LEN is in include/linux/netdevice.h which is not part of user exported api.

Quoted 3 lines

cheers,
jamal

#11 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 3 lines · Jiri Pirko

Jamal, please look at the patch & code. MAX_PHYS_PORT_ID_LEN is in include/linux/netdevice.h which is not part of user exported api.

I got it - the confusing part was rtnetlink.c was looking for it as if it was expecting user space to send it.

cheers,
jamal

maintainer
#12 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

In reply to Jamal Hadi Salim

From: Jamal Hadi Salim <[email protected]>
Date: Mon, 10 Nov 2014 07:17:04 -0500

Quoted 5 lines · Jiri Pirko
Quoted 4 lines

Mon, Nov 10, 2014 at 04:35:12AM CET, [email protected] wrote:

I don't see a reason why this would break kabi:

Quoted 7 lines

include/linux/netdevice.h struct netdev_fcoe_hbainfo { · line 756

Quoted 3 lines
include/linux/netdevice.h +1 -1
-#define MAX_PHYS_PORT_ID_LEN 32
+#define MAX_PHYS_ITEM_ID_LEN 32

refer to my response to Dave. Just define MAX_PHYS_PORT_ID_LEN to MAX_PHYS_ITEM_ID_LEN so people dont have to change their code because a name change.

Again, nobody has to change anything.

This macro is not visible outside of the kernel.

Jamal, this is really driving me crazy, this is a non-issue.

#13 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

Quoted 5 lines · David Miller

From: Jamal Hadi Salim <[email protected]>

Jamal, this is really driving me crazy, this is a non-issue.

You are right Dave it is a non-issue, I am sorry. I was still humping on the wrong tree on the attribute size change.

But please let us have the discussion so the right thing can happen. I am not trying to beat up on Jiri. I actually think he is doing the right thing; we just need to make sure input from other people is taken into consideration because they have implemented on real devices.

cheers,
jamal

Acked-by on v2 1/10
#14 lore raw

Re: [patch net-next v2 01/10] net: rename netdev_phys_port_id to more generic name

In reply to Jiri Pirko
Quoted 4 lines · Jiri Pirko

So this can be reused for identification of other "items" as well.

---

Looks good to me. Just a simple code refactoring and doesn't touch any user visible uapi files and makes the next patches a bit cleaner.

Signature · 1 line
John Fastabend         Intel Corporation
author maintainer
#15 lore raw

PATCH v2 2/10 net: introduce generic switch devices support

In reply to Jiri Pirko

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.

---
 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
Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
 F:	arch/*/kernel/pci-swiotlb.c
 F:	include/linux/swiotlb.h
 
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
 SYNOPSYS ARC ARCHITECTURE
 M:	Vineet Gupta <[email protected]>
 S:	Supported
include/linux/netdevice.h +10 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
+							struct netdev_phys_item_id *psid);
+#endif
 };
 
 /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +33 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_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_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);
Signature · 1 line
1.9.3
#16 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 74 lines · Jiri Pirko

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.

---
  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

Documentation/networking/switchdev.txt new file +43 -0
new file mode 100644
index 0000000..98be76c
@@ -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"

Documentation/networking/switchdev.txt line 53

Quoted 10 lines
Documentation/networking/switchdev.txt new file +10 -0
+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_sw_parent_get_id - 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.

What is the connection between ndo_sw_parent_get_id and ndo_get_phys_port_id(). I'm having a bit of trouble teasing this out.

For example here is my ascii art for a SR-IOV NIC,

eth0 eth1 eth2
| | |
| | |
PF VF VF

   +----+---------+--------+----+
   |       embedded bridge      |
   +-------------+--------------+
                 |

port

that can do switching between the various uplinks and downlinks. In IEEE 802.1Q language the embedded bridge acts like an edge relay. At least that seems to be the current state of the art for SR-IOV. Edge relay just means it has a single uplink port to the network and multiple downlinks and also isn't required to do learning and run loop detection protocols STP, et. al.

Also there are multi-function devices that look the same except replace the VFs with PFs. It seems to be a common mode for NICs that do the iSCSI offloads with storage functions.

When something is an embedded bridge vs a SOME switch chip is not entirely clear.

My understanding is use ndo_sw_parent_get_id() when you have multiple physical ports all connected to a single switch object. When you have a single port connected to multiple PCIE functions or queues representing a netdev (e.g. macvlan offload) use the ndo_get_phys_port_id(). Just want to be sure we are on the same page here.

Otherwise patch looks good. I think we can clear the above up with an addition to the documentation. Could go in after the initial set and be OK with me.

IMO this patch is needed otherwise user space is at a complete loss on trying to figure out how netdevs map to switch silicon. You could have reused ndo_get_phys_port_id() perhaps but then I think user space may get confused by SR-IOV/VMDQ/etc ports attached to a switch silicon. For .02$ having a new distinct identifier is cleaner.

Documentation/networking/switchdev.txt line 59

Quoted 6 lines
Documentation/networking/switchdev.txt new file +6 -0
+	ndo_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.

[...]

Thanks,
John

Signature · 1 line
John Fastabend         Intel Corporation
author maintainer
#17 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 116 lines · Mon, Nov 10, 2014 at 10:59:38PM CET, [email protected] wrote:
Quoted 74 lines · Jiri Pirko

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.

---
 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
Documentation/networking/switchdev.txt new file +43 -0
new file mode 100644
index 0000000..98be76c
@@ -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"

Documentation/networking/switchdev.txt line 53

Quoted 10 lines
Documentation/networking/switchdev.txt new file +10 -0
+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_sw_parent_get_id - 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.

What is the connection between ndo_sw_parent_get_id and ndo_get_phys_port_id(). I'm having a bit of trouble teasing this out.

For example here is my ascii art for a SR-IOV NIC,

eth0 eth1 eth2
| | |
| | |
PF VF VF

  +----+---------+--------+----+
  |       embedded bridge      |
  +-------------+--------------+
                |

port

that can do switching between the various uplinks and downlinks. In IEEE 802.1Q language the embedded bridge acts like an edge relay. At least that seems to be the current state of the art for SR-IOV. Edge relay just means it has a single uplink port to the network and multiple downlinks and also isn't required to do learning and run loop detection protocols STP, et. al.

Also there are multi-function devices that look the same except replace the VFs with PFs. It seems to be a common mode for NICs that do the iSCSI offloads with storage functions.

When something is an embedded bridge vs a SOME switch chip is not entirely clear.

Quoted 6 lines

My understanding is use ndo_sw_parent_get_id() when you have multiple physical ports all connected to a single switch object. When you have a single port connected to multiple PCIE functions or queues representing a netdev (e.g. macvlan offload) use the ndo_get_phys_port_id(). Just want to be sure we are on the same page here.

Nod. You described that right.

Quoted 11 lines

Otherwise patch looks good. I think we can clear the above up with an addition to the documentation. Could go in after the initial set and be OK with me.

IMO this patch is needed otherwise user space is at a complete loss on trying to figure out how netdevs map to switch silicon. You could have reused ndo_get_phys_port_id() perhaps but then I think user space may get confused by SR-IOV/VMDQ/etc ports attached to a switch silicon. For .02$ having a new distinct identifier is cleaner.

It most definitelly is. Therefore I went that way.

Quoted 17 lines

Documentation/networking/switchdev.txt line 59

Quoted 8 lines
Documentation/networking/switchdev.txt new file +6 -0
+	ndo_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.

[...]

Thanks,
John

Signature · 1 line
John Fastabend         Intel Corporation
#18 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

In reply to Jiri Pirko

Am 09.11.2014 um 11:51 schrieb Jiri Pirko:

Documentation/networking/switchdev.txt

Quoted 2 lines
Documentation/networking/switchdev.txt +1 -0
+	ndo_sw_parent_get_id - ...

here the ndo is called get_id

but

include/linux/netdevice.h struct net_device_ops { · line 1175

Quoted 7 lines
include/linux/netdevice.h +5 -0
+ *
+ * int (*ndo_sw_parent_id_get)(struct net_device *dev,
+ *			       struct netdev_phys_item_id *psid);
@@ -1168,6 +1174,10 @@ struct net_device_ops {
+	int			(*ndo_sw_parent_id_get)(struct net_device *dev,
+							struct netdev_phys_item_id *psid);

here it is call id_get, which is similar but not the same.

Regards,
M. Braun

author maintainer
#19 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 10 lines · Tue, Nov 11, 2014 at 10:49:36AM CET, [email protected] wrote:

Am 09.11.2014 um 11:51 schrieb Jiri Pirko:

Documentation/networking/switchdev.txt

Quoted 2 lines
Documentation/networking/switchdev.txt +1 -0
+	ndo_sw_parent_get_id - ...

here the ndo is called get_id

but

Quoted 9 lines

include/linux/netdevice.h struct net_device_ops { · line 1175

Quoted 7 lines
include/linux/netdevice.h +5 -0
+ *
+ * int (*ndo_sw_parent_id_get)(struct net_device *dev,
+ *			       struct netdev_phys_item_id *psid);
@@ -1168,6 +1174,10 @@ struct net_device_ops {
+	int			(*ndo_sw_parent_id_get)(struct net_device *dev,
+							struct netdev_phys_item_id *psid);

here it is call id_get, which is similar but not the same.

Will fix the docs, thanks.

Quoted 3 lines

Regards,
M. Braun

#20 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

In reply to Jiri Pirko
Quoted 126 lines · Jiri Pirko

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.

---
  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

Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
  F:	arch/*/kernel/pci-swiotlb.c
  F:	include/linux/swiotlb.h
 
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
  SYNOPSYS ARC ARCHITECTURE
  M:	Vineet Gupta <[email protected]>
  S:	Supported
include/linux/netdevice.h +6 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);

include/linux/netdevice.h struct net_device_ops { · line 1179

Quoted 6 lines
include/linux/netdevice.h +3 -0
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
+							struct netdev_phys_item_id *psid);

Can we keep the name generic and not include "sw" which implies switch here ?.
I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for them in other offload scenarios in the future. This particular ndo can be just ndo_parent_id_get().
And the others that do specific offloads can have "offload" in them if required..?.

Quoted 132 lines
include/linux/netdevice.h +1 -0
+#endif
  };
 
  /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +33 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_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_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);
author maintainer
#21 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 131 lines · Wed, Nov 19, 2014 at 02:28:10PM CET, [email protected] wrote:
Quoted 130 lines · Jiri Pirko

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.

---
 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
Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
 F:	arch/*/kernel/pci-swiotlb.c
 F:	include/linux/swiotlb.h
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
 SYNOPSYS ARC ARCHITECTURE
 M:	Vineet Gupta <[email protected]>
 S:	Supported
include/linux/netdevice.h +8 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
Quoted 8 lines

include/linux/netdevice.h struct net_device_ops { · line 1179

Quoted 1 line
include/linux/netdevice.h +1 -0
+							struct netdev_phys_item_id *psid);

Can we keep the name generic and not include "sw" which implies switch here ?.
I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for them in other offload scenarios in the future.
This particular ndo can be just ndo_parent_id_get().
And the others that do specific offloads can have "offload" in them if required..?.

But this is for getting parent switch id, sw should be there. If comes a time when this might be reused to something else, we change it then. This is internal api, easily changeable.

Quoted 134 lines
Quoted 133 lines
include/linux/netdevice.h +1 -0
+#endif
 };
 /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +33 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_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_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);
#22 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 141 lines · Jiri Pirko
Quoted 131 lines · Wed, Nov 19, 2014 at 02:28:10PM CET, [email protected] wrote:
Quoted 130 lines · Jiri Pirko

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.

---
  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

Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
  F:	arch/*/kernel/pci-swiotlb.c
  F:	include/linux/swiotlb.h
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
  SYNOPSYS ARC ARCHITECTURE
  M:	Vineet Gupta <[email protected]>
  S:	Supported
include/linux/netdevice.h +8 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
Quoted 8 lines

include/linux/netdevice.h struct net_device_ops { · line 1179

Quoted 1 line
include/linux/netdevice.h +1 -0
+							struct netdev_phys_item_id *psid);

Can we keep the name generic and not include "sw" which implies switch here ?.
I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for them in other offload scenarios in the future.
This particular ndo can be just ndo_parent_id_get().
And the others that do specific offloads can have "offload" in them if required..?.

Quoted 1 line

But this is for getting parent switch id, sw should be there.

Since we have not figured out the details or namespace for switchd ids yet, its still some parent id to me.

Quoted 3 lines

If comes a
time when this might be reused to something else, we change it then. This is internal api, easily changeable.

also, "sw" seems more "software" than "switch".

Quoted 137 lines
Quoted 125 lines
Quoted 125 lines
include/linux/netdevice.h +1 -0
+#endif
  };
  /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +25 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid)
Quoted 8 lines

net/switchdev/switchdev.c line 33

Quoted 8 lines
net/switchdev/switchdev.c new file +8 -0
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if (!ops->ndo_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#23 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 144 lines · Roopa Prabhu
Quoted 141 lines · Jiri Pirko
Quoted 131 lines · Wed, Nov 19, 2014 at 02:28:10PM CET, [email protected] wrote:
Quoted 130 lines · Jiri Pirko

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.

---
 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
Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
 F:	arch/*/kernel/pci-swiotlb.c
 F:	include/linux/swiotlb.h
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
 SYNOPSYS ARC ARCHITECTURE
 M:	Vineet Gupta <[email protected]>
 S:	Supported
include/linux/netdevice.h +8 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
Quoted 8 lines

include/linux/netdevice.h struct net_device_ops { · line 1179

Quoted 1 line
include/linux/netdevice.h +1 -0
+							struct netdev_phys_item_id *psid);

Can we keep the name generic and not include "sw" which implies switch here ?.
I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for them in other offload scenarios in the future.
This particular ndo can be just ndo_parent_id_get().
And the others that do specific offloads can have "offload" in them if required..?.

Quoted 1 line

But this is for getting parent switch id, sw should be there.

Quoted 7 lines

Since we have not figured out the details or namespace for switchd ids yet, its still some parent id to me.

Quoted 3 lines

If comes a
time when this might be reused to something else, we change it then. This is internal api, easily changeable.

also, "sw" seems more "software" than "switch".

I had voiced this same concern when we met and discussed this in Dusseldorf. Let's move to another name such as 'hw' (since we really are talking about hardware abstraction) or 'offload.' Just using 'sw' is confusing as many will not read it as switch.

I'll be happy to post a fix based on your devel patches.

Quoted 139 lines
Quoted 138 lines
Quoted 126 lines
Quoted 126 lines
include/linux/netdevice.h +1 -0
+#endif
 };
 /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +25 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid)
Quoted 8 lines

net/switchdev/switchdev.c line 33

Quoted 8 lines
net/switchdev/switchdev.c new file +8 -0
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if (!ops->ndo_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#24 lore raw

Re: [patch net-next v2 02/10] net: introduce generic switch devices support

Quoted 151 lines · Thu, Nov 20, 2014 at 04:55:41PM CET, [email protected] wrote:
Quoted 150 lines · Roopa Prabhu
Quoted 141 lines · Jiri Pirko
Quoted 131 lines · Wed, Nov 19, 2014 at 02:28:10PM CET, [email protected] wrote:
Quoted 130 lines · Jiri Pirko

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.

---
 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
Documentation/networking/switchdev.txt new file +59 -0
new file mode 100644
index 0000000..98be76c
@@ -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_sw_parent_get_id - 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_sw_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_sw_port_* - Functions that serve for a port-specific manipulation.
MAINTAINERS +7 -0
index 3a41fb0..776e078 100644
@@ -9003,6 +9003,13 @@ F:	lib/swiotlb.c
 F:	arch/*/kernel/pci-swiotlb.c
 F:	include/linux/swiotlb.h
+SWITCHDEV
+M:	Jiri Pirko <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	net/switchdev/
+F:	include/net/switchdev.h
+
 SYNOPSYS ARC ARCHITECTURE
 M:	Vineet Gupta <[email protected]>
 S:	Supported
include/linux/netdevice.h +8 -0
index 71922e0..97eade9 100644
@@ -1017,6 +1017,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_sw_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);
@@ -1168,6 +1174,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_sw_parent_id_get)(struct net_device *dev,
Quoted 8 lines

include/linux/netdevice.h struct net_device_ops { · line 1179

Quoted 1 line
include/linux/netdevice.h +1 -0
+							struct netdev_phys_item_id *psid);

Can we keep the name generic and not include "sw" which implies switch here ?.
I understand that it is under CONFIG_NET_SWITCHDEV but we might find use for them in other offload scenarios in the future.
This particular ndo can be just ndo_parent_id_get().
And the others that do specific offloads can have "offload" in them if required..?.

Quoted 1 line

But this is for getting parent switch id, sw should be there.

Since we have not figured out the details or namespace for switchd ids yet, its still some parent id to me.

Quoted 3 lines

If comes a
time when this might be reused to something else, we change it then. This is internal api, easily changeable.

Quoted 8 lines
Quoted 1 line

also, "sw" seems more "software" than "switch".

I had voiced this same concern when we met and discussed this in Dusseldorf. Let's move to another name such as 'hw' (since we really are talking about hardware abstraction) or 'offload.' Just using 'sw' is confusing as many will not read it as switch.

I'll be happy to post a fix based on your devel patches.

Np, I'll take care of it.

Quoted 141 lines
Quoted 141 lines
Quoted 140 lines
Quoted 128 lines
Quoted 128 lines
include/linux/netdevice.h +1 -0
+#endif
 };
 /**
include/net/switchdev.h new file +30 -0
new file mode 100644
index 0000000..79bf9bd
@@ -0,0 +1,30 @@
+/*
+ * include/net/switchdev.h - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/netdevice.h>
+
+#ifdef CONFIG_NET_SWITCHDEV
+
+int netdev_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid);
+
+#else
+
+static inline int netdev_sw_parent_id_get(struct net_device *dev,
+					  struct netdev_phys_item_id *psid)
+{
+	return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif /* _LINUX_SWITCHDEV_H_ */
net/Kconfig +1 -0
index 99815b5..ff9ffc1 100644
@@ -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
net/Makefile +3 -0
index 7ed1970..95fc694 100644
@@ -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
net/switchdev/Kconfig new file +13 -0
new file mode 100644
index 0000000..1557545
@@ -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.
net/switchdev/Makefile new file +5 -0
new file mode 100644
index 0000000..5ed63ed
@@ -0,0 +1,5 @@
+#
+# Makefile for the Switch device API
+#
+
+obj-$(CONFIG_NET_SWITCHDEV) += switchdev.o
net/switchdev/switchdev.c new file +25 -0
new file mode 100644
index 0000000..5010f646
@@ -0,0 +1,33 @@
+/*
+ * net/switchdev/switchdev.c - Switch device API
+ * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/switchdev.h>
+
+/**
+ *	netdev_sw_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_sw_parent_id_get(struct net_device *dev,
+			    struct netdev_phys_item_id *psid)
Quoted 8 lines

net/switchdev/switchdev.c line 33

Quoted 8 lines
net/switchdev/switchdev.c new file +8 -0
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if (!ops->ndo_sw_parent_id_get)
+		return -EOPNOTSUPP;
+	return ops->ndo_sw_parent_id_get(dev, psid);
+}
+EXPORT_SYMBOL(netdev_sw_parent_id_get);

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#25 lore raw

PATCH v2 3/10 rtnl: expose physical switch id for particular device

In reply to Jiri Pirko

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.

---
 include/uapi/linux/if_link.h |  1 +
 net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +1 -0
index 7072d83..4163753 100644
@@ -145,6 +145,7 @@ enum {
 	IFLA_CARRIER,
 	IFLA_PHYS_PORT_ID,
 	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,
 	__IFLA_MAX
 };
 
net/core/rtnetlink.c +25 -1
index 1087c6d..f839354 100644
@@ -43,6 +43,7 @@
 
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <net/switchdev.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -868,7 +869,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)
@@ -967,6 +969,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_sw_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)
@@ -1039,6 +1059,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)
@@ -1198,6 +1221,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] = {
Signature · 1 line
1.9.3
#26 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

Quoted 25 lines · Jiri Pirko

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.

---
  include/uapi/linux/if_link.h |  1 +
  net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
  2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +1 -0
index 7072d83..4163753 100644
@@ -145,6 +145,7 @@ enum {
  	IFLA_CARRIER,
  	IFLA_PHYS_PORT_ID,
  	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,
  	__IFLA_MAX
  };
 

include/uapi/linux/if_link.h static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · line 1226

Quoted 6 lines
include/uapi/linux/if_link.h +1 -0
@@ -1198,6 +1221,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 },
  };
 

Ok, looking at this compared to #1 i can see you are introducing IFLA_PHYS_SWITCH_ID but then why did you need to change IFLA_PHYS_PORT_ID earlier?

cheers,
jamal

Quoted 2 lines
include/uapi/linux/if_link.h +0 -0
  static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
author maintainer
#27 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

Quoted 25 lines · Mon, Nov 10, 2014 at 04:43:58AM CET, [email protected] wrote:
Quoted 22 lines · Jiri Pirko

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.

---
 include/uapi/linux/if_link.h |  1 +
 net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +1 -0
index 7072d83..4163753 100644
@@ -145,6 +145,7 @@ enum {
 	IFLA_CARRIER,
 	IFLA_PHYS_PORT_ID,
 	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,
 	__IFLA_MAX
 };
 
Quoted 11 lines

include/uapi/linux/if_link.h static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · line 1226

Quoted 7 lines
include/uapi/linux/if_link.h +1 -0
@@ -1198,6 +1221,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 },
 };
 

Ok, looking at this compared to #1 i can see you are introducing IFLA_PHYS_SWITCH_ID but then why did you need to change IFLA_PHYS_PORT_ID earlier?

I did not change it at all. I only made the name more generic. Please look closer to the patch 1.

Quoted 7 lines

cheers,
jamal

Quoted 2 lines
include/uapi/linux/if_link.h +0 -0
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
#28 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

In reply to Jiri Pirko
Quoted 15 lines · Jiri Pirko

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.

---
  include/uapi/linux/if_link.h |  1 +
  net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
  2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +0 -0
index 7072d83..4163753 100644

include/uapi/linux/if_link.h enum { · line 148

Quoted 4 lines
include/uapi/linux/if_link.h +1 -0
@@ -145,6 +145,7 @@ enum {
  	IFLA_CARRIER,
  	IFLA_PHYS_PORT_ID,
  	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,

Jiri, since we have not really converged on the switchdev class or having a separate switchdev instance,
am thinking it is better if we dont expose any such switch_id to userspace yet until absolutely needed. Do you need it today ? There is no real in kernel hw switch driver that will use it today. And quite likely this will need to change when we introduce real hw switch drivers.

Quoted 68 lines
include/uapi/linux/if_link.h +0 -0
  	__IFLA_MAX
  };
 
net/core/rtnetlink.c +25 -1
index 1087c6d..f839354 100644
@@ -43,6 +43,7 @@
 
  #include <linux/inet.h>
  #include <linux/netdevice.h>
+#include <net/switchdev.h>
  #include <net/ip.h>
  #include <net/protocol.h>
  #include <net/arp.h>
@@ -868,7 +869,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)
@@ -967,6 +969,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_sw_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)
@@ -1039,6 +1059,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)
@@ -1198,6 +1221,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] = {
#29 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

Quoted 23 lines · Roopa Prabhu
Quoted 16 lines · Jiri Pirko

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.

---
  include/uapi/linux/if_link.h |  1 +
  net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
  2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +0 -0
index 7072d83..4163753 100644

include/uapi/linux/if_link.h enum { · line 148

Quoted 4 lines
include/uapi/linux/if_link.h +1 -0
@@ -145,6 +145,7 @@ enum {
        IFLA_CARRIER,
        IFLA_PHYS_PORT_ID,
        IFLA_CARRIER_CHANGES,
+       IFLA_PHYS_SWITCH_ID,
Quoted 7 lines

Jiri, since we have not really converged on the switchdev class or having a separate switchdev instance,
am thinking it is better if we dont expose any such switch_id to userspace yet until absolutely needed. Do you need it today ?
There is no real in kernel hw switch driver that will use it today. And quite likely this will need to change when we introduce real hw switch drivers.

How will it change when real hw switch drivers are introduced? Will the real sw driver not be able to give a up unique ID for the switch?

#30 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

Quoted 29 lines · Scott Feldman
Quoted 21 lines · Roopa Prabhu
Quoted 15 lines · Jiri Pirko

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.

---
   include/uapi/linux/if_link.h |  1 +
   net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
   2 files changed, 26 insertions(+), 1 deletion(-)
include/uapi/linux/if_link.h +0 -0
index 7072d83..4163753 100644

include/uapi/linux/if_link.h enum { · line 148

Quoted 4 lines
include/uapi/linux/if_link.h +1 -0
@@ -145,6 +145,7 @@ enum {
         IFLA_CARRIER,
         IFLA_PHYS_PORT_ID,
         IFLA_CARRIER_CHANGES,
+       IFLA_PHYS_SWITCH_ID,
Quoted 7 lines

Jiri, since we have not really converged on the switchdev class or having a separate switchdev instance,
am thinking it is better if we dont expose any such switch_id to userspace yet until absolutely needed. Do you need it today ?
There is no real in kernel hw switch driver that will use it today. And quite likely this will need to change when we introduce real hw switch drivers.

Quoted 2 lines

How will it change when real hw switch drivers are introduced? Will the real sw driver not be able to give a up unique ID for the switch?

With my question i was trying to see if there are other ways to manage
the relationship between the
switch device and the ports, instead of an random id provided by each switch driver. Today the switch id namespace seems to be with each switch driver. On my systems on the first switch chip quite likely i will choose an id 0.,,and possibly some other driver will choose the same id. The switch id namespace handling was not clear to me.

But, to your question, am sure we will have some id to go in there since the field is now available.

Thanks,
Roopa

author maintainer
#31 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

In reply to Roopa Prabhu
Quoted 11 lines · Mon, Nov 10, 2014 at 06:58:08PM CET, [email protected] wrote:
Quoted 10 lines · Jiri Pirko

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.

---
 include/uapi/linux/if_link.h |  1 +
 net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
 2 files changed, 26 insertions(+), 1 deletion(-)
Quoted 16 lines

include/uapi/linux/if_link.h enum { · line 148

Quoted 9 lines
include/uapi/linux/if_link.h +1 -0
index 7072d83..4163753 100644
@@ -145,6 +145,7 @@ enum {
 	IFLA_CARRIER,
 	IFLA_PHYS_PORT_ID,
 	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,

Jiri, since we have not really converged on the switchdev class or having a separate switchdev instance,
am thinking it is better if we dont expose any such switch_id to userspace yet until absolutely needed. Do you need it today ?
There is no real in kernel hw switch driver that will use it today. And quite likely this will need to change when we introduce real hw switch drivers.

When and if the switchdev class is introduced, switch id can happily live on. It is nothing against it. Userspace should use this id to group the ports of physical switch.

Quoted 65 lines
Quoted 64 lines
include/uapi/linux/if_link.h +0 -0
 	__IFLA_MAX
 };
net/core/rtnetlink.c +25 -1
index 1087c6d..f839354 100644
@@ -43,6 +43,7 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <net/switchdev.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -868,7 +869,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)
@@ -967,6 +969,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_sw_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)
@@ -1039,6 +1059,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)
@@ -1198,6 +1221,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] = {
#32 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

Quoted 29 lines · Jiri Pirko
Quoted 11 lines · Mon, Nov 10, 2014 at 06:58:08PM CET, [email protected] wrote:
Quoted 10 lines · Jiri Pirko

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.

---
  include/uapi/linux/if_link.h |  1 +
  net/core/rtnetlink.c         | 26 +++++++++++++++++++++++++-
  2 files changed, 26 insertions(+), 1 deletion(-)
Quoted 16 lines

include/uapi/linux/if_link.h enum { · line 148

Quoted 9 lines
include/uapi/linux/if_link.h +1 -0
index 7072d83..4163753 100644
@@ -145,6 +145,7 @@ enum {
  	IFLA_CARRIER,
  	IFLA_PHYS_PORT_ID,
  	IFLA_CARRIER_CHANGES,
+	IFLA_PHYS_SWITCH_ID,

Jiri, since we have not really converged on the switchdev class or having a separate switchdev instance,
am thinking it is better if we dont expose any such switch_id to userspace yet until absolutely needed. Do you need it today ?
There is no real in kernel hw switch driver that will use it today. And quite likely this will need to change when we introduce real hw switch drivers.

Quoted 5 lines

When and if the switchdev class is introduced, switch id can happily live on. It is nothing against it. Userspace should use this id to group the ports of physical switch.

+1 I think we need this otherwise how will userspace "know" how the ports are related? If I have two switch silicon blocks in a single platform or perhaps have a switch silicon with traditional host nics on the same platform.

Signature · 1 line
John Fastabend         Intel Corporation
Acked-by on v2 3/10
#33 lore raw

Re: [patch net-next v2 03/10] rtnl: expose physical switch id for particular device

In reply to Jiri Pirko
Quoted 6 lines · Jiri Pirko

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.

---

Yep, I need something like this for my management app to learn how the switch is laid out. This becomes more relevant if I have switch silicon mixed with NICs that are not connected to the switch object in the same platform.

Signature · 1 line
John Fastabend         Intel Corporation
author maintainer
#34 lore raw

PATCH v2 4/10 net-sysfs: expose physical switch id for particular device

In reply to Jiri Pirko
---
 net/core/net-sysfs.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
net/core/net-sysfs.c +24 -0
index 55dc4da..8e6603c 100644
@@ -12,6 +12,7 @@
 #include <linux/capability.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <net/switchdev.h>
 #include <linux/if_arp.h>
 #include <linux/slab.h>
 #include <linux/nsproxy.h>
@@ -399,6 +400,28 @@ static ssize_t phys_port_id_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(phys_port_id);
 
+static ssize_t phys_switch_id_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	ssize_t ret = -EINVAL;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	if (dev_isalive(netdev)) {
+		struct netdev_phys_item_id ppid;
+
+		ret = netdev_sw_parent_id_get(netdev, &ppid);
+		if (!ret)
+			ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id);
+	}
+	rtnl_unlock();
+
+	return ret;
+}
+static DEVICE_ATTR_RO(phys_switch_id);
+
 static struct attribute *net_class_attrs[] = {
 	&dev_attr_netdev_group.attr,
 	&dev_attr_type.attr,
@@ -423,6 +446,7 @@ static struct attribute *net_class_attrs[] = {
 	&dev_attr_flags.attr,
 	&dev_attr_tx_queue_len.attr,
 	&dev_attr_phys_port_id.attr,
+	&dev_attr_phys_switch_id.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(net_class);
Signature · 1 line
1.9.3
author maintainer
#36 lore raw

PATCH v2 5/10 rocker: introduce rocker switch driver

In reply to Jiri Pirko

This patch introduces the first driver to benefit from the switchdev infrastructure and to implement newly introduced switch ndos. This is a driver for emulated switch chip implemented in qemu:
https://github.com/sfeldma/qemu-rocker/

This patch is a result of joint work with Scott Feldman.

---
 MAINTAINERS                          |    7 +
 drivers/net/ethernet/Kconfig         |    1 +
 drivers/net/ethernet/Makefile        |    1 +
 drivers/net/ethernet/rocker/Kconfig  |   27 +
 drivers/net/ethernet/rocker/Makefile |    5 +
 drivers/net/ethernet/rocker/rocker.c | 2060 ++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h |  427 +++++++
 7 files changed, 2528 insertions(+)
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h
MAINTAINERS +7 -0
index 776e078..7e15b50 100644
@@ -7807,6 +7807,13 @@ F:	drivers/hid/hid-roccat*
 F:	include/linux/hid-roccat*
 F:	Documentation/ABI/*/sysfs-driver-hid-roccat*
 
+ROCKER DRIVER
+M:	Jiri Pirko <[email protected]>
+M:	Scott Feldman <[email protected]>
+L:	[email protected]
+S:	Supported
+F:	drivers/net/ethernet/rocker/
+
 ROCKETPORT DRIVER
 P:	Comtrol Corp.
 W:	http://www.comtrol.com
drivers/net/ethernet/Kconfig +1 -0
index 1ed1fbb..df76050 100644
@@ -155,6 +155,7 @@ source "drivers/net/ethernet/qualcomm/Kconfig"
 source "drivers/net/ethernet/realtek/Kconfig"
 source "drivers/net/ethernet/renesas/Kconfig"
 source "drivers/net/ethernet/rdc/Kconfig"
+source "drivers/net/ethernet/rocker/Kconfig"
 
 config S6GMAC
 	tristate "S6105 GMAC ethernet support"
drivers/net/ethernet/Makefile +1 -0
index 6e0b629..bf56f8b 100644
@@ -65,6 +65,7 @@ obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
 obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_SH_ETH) += renesas/
 obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
+obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
 obj-$(CONFIG_S6GMAC) += s6gmac.o
 obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
 obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
drivers/net/ethernet/rocker/Kconfig new file +27 -0
new file mode 100644
index 0000000..11a850e
@@ -0,0 +1,27 @@
+#
+# Rocker device configuration
+#
+
+config NET_VENDOR_ROCKER
+	bool "Rocker devices"
+	default y
+	---help---
+	  If you have a network device belonging to this class, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Rocker devices. If you say Y, you will be asked for
+	  your specific card in the following questions.
+
+if NET_VENDOR_ROCKER
+
+config ROCKER
+	tristate "Rocker switch driver (EXPERIMENTAL)"
+	depends on PCI && NET_SWITCHDEV
+	---help---
+	  This driver supports Rocker switch device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rocker.
+
+endif # NET_VENDOR_ROCKER
drivers/net/ethernet/rocker/Makefile new file +5 -0
new file mode 100644
index 0000000..f85fb12
@@ -0,0 +1,5 @@
+#
+# Makefile for the Rocker network device drivers.
+#
+
+obj-$(CONFIG_ROCKER) += rocker.o
drivers/net/ethernet/rocker/rocker.c new file +2060 -0

2,060 lines not on this page · raw message

drivers/net/ethernet/rocker/rocker.h new file +427 -0

427 lines not on this page · raw message

Signature · 1 line
1.9.3
Reviewed-by on v2 5/10
#37 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 23 lines · Jiri Pirko

This patch introduces the first driver to benefit from the switchdev infrastructure and to implement newly introduced switch ndos. This is a driver for emulated switch chip implemented in qemu:
https://github.com/sfeldma/qemu-rocker/

This patch is a result of joint work with Scott Feldman.

---
  MAINTAINERS                          |    7 +
  drivers/net/ethernet/Kconfig         |    1 +
  drivers/net/ethernet/Makefile        |    1 +
  drivers/net/ethernet/rocker/Kconfig  |   27 +
  drivers/net/ethernet/rocker/Makefile |    5 +
  drivers/net/ethernet/rocker/rocker.c | 2060 ++++++++++++++++++++++++++++++++++
  drivers/net/ethernet/rocker/rocker.h |  427 +++++++
  7 files changed, 2528 insertions(+)

create mode 100644 drivers/net/ethernet/rocker/Kconfig create mode 100644 drivers/net/ethernet/rocker/Makefile create mode 100644 drivers/net/ethernet/rocker/rocker.c create mode 100644 drivers/net/ethernet/rocker/rocker.h

[...]

drivers/net/ethernet/rocker/rocker.c line 1534

Quoted 13 lines
drivers/net/ethernet/rocker/rocker.c new file +13 -0
+
+static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_desc_info *desc_info;
+	struct rocker_tlv *frags;
+	int i;
+	int err;
+
+	desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+	if (unlikely(!desc_info)) {
+		if (net_ratelimit())

Could you have a netif_stop_queue() here as well same as below? Not that optimizing the xmit routine is the interesting part of this patch. But I guess this is just some strange error path because I see you check this case below.

Quoted 23 lines
drivers/net/ethernet/rocker/rocker.c new file +23 -0
+			netdev_err(dev, "tx ring full when queue awake\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	rocker_desc_cookie_ptr_set(desc_info, skb);
+
+	frags = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAGS);
+	if (!frags)
+		goto out;
+	err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+					  skb->data, skb_headlen(skb));
+	if (err)
+		goto nest_cancel;
+	if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX)
+		goto nest_cancel;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+						  skb_frag_address(frag),
+						  skb_frag_size(frag));
+		if (err)

drivers/net/ethernet/rocker/rocker.c line 1567

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+			goto unmap_frags;
+	}
+	rocker_tlv_nest_end(desc_info, frags);
+
+	rocker_desc_gen_clear(desc_info);
+	rocker_desc_head_set(rocker, &rocker_port->tx_ring, desc_info);
+
+	desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+	if (!desc_info)
+		netif_stop_queue(dev);

I'm not entirely sure I followed the TLV usage here but OK. If it works...

Quoted 24 lines
drivers/net/ethernet/rocker/rocker.c new file +24 -0
+
+	return NETDEV_TX_OK;
+
+unmap_frags:
+	rocker_tx_desc_frags_unmap(rocker_port, desc_info);
+nest_cancel:
+	rocker_tlv_nest_cancel(desc_info, frags);
+out:
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int rocker_port_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	int err;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	err = rocker_cmd_set_port_settings_macaddr(rocker_port, addr->sa_data);
+	if (err)
+		return err;

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

Quoted 37 lines
drivers/net/ethernet/rocker/rocker.c new file +37 -0
+	psid->id_len = sizeof(rocker->hw.id);
+	memcpy(&psid->id, &rocker->hw.id, psid->id_len);
+	return 0;
+}
+
+static const struct net_device_ops rocker_port_netdev_ops = {
+	.ndo_open			= rocker_port_open,
+	.ndo_stop			= rocker_port_stop,
+	.ndo_start_xmit			= rocker_port_xmit,
+	.ndo_set_mac_address		= rocker_port_set_mac_address,
+	.ndo_sw_parent_id_get		= rocker_port_sw_parent_id_get,
+};
+
+/********************
+ * ethtool interface
+ ********************/
+
+static int rocker_port_get_settings(struct net_device *dev,
+				    struct ethtool_cmd *ecmd)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+
+	return rocker_cmd_get_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static int rocker_port_set_settings(struct net_device *dev,
+				    struct ethtool_cmd *ecmd)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+
+	return rocker_cmd_set_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static void rocker_port_get_drvinfo(struct net_device *dev,
+				    struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver));

drivers/net/ethernet/rocker/rocker.c line 1648

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+	strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static const struct ethtool_ops rocker_port_ethtool_ops = {
+	.get_settings		= rocker_port_get_settings,
+	.set_settings		= rocker_port_set_settings,
+	.get_drvinfo		= rocker_port_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
+

[...]

Looks reasonable to me, although I mostly scanned it and looked over the interface parts. My comments are just observations no need to change anything for them.

Signature · 1 line
John Fastabend         Intel Corporation
#38 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

Is the goal to expose a hardware ID here to allow identification of the hardware chip?

MAC is tempting but I'm pretty sure that we'll have pure L3 devices being handled by this API at some point.

author maintainer
#39 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 13 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

Quoted 3 lines

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

This is something similar to physical port id. Each driver should take care of generating that id.

Quoted 6 lines

Is the goal to expose a hardware ID here to allow identification of the hardware chip?

MAC is tempting but I'm pretty sure that we'll have pure L3 devices being handled by this API at some point.

#40 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 14 lines · Jiri Pirko
Quoted 13 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

Quoted 6 lines
Quoted 3 lines

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

This is something similar to physical port id. Each driver should take care of generating that id.

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Even now, multiple rocker instances would have the same ID.

author maintainer
#41 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 19 lines · Tue, Nov 11, 2014 at 04:32:32PM CET, [email protected] wrote:
Quoted 18 lines · Jiri Pirko
Quoted 16 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

Quoted 6 lines
Quoted 2 lines

This is something similar to physical port id. Each driver should take care of generating that id.

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Well, as I said, it is the same as for physical port id. But if needed, there can be added some simple mechanism for the id registration ensuring their uniqueness.

Quoted 2 lines

Even now, multiple rocker instances would have the same ID.

It depends on what hw returns to driver.

#42 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 5 lines · Jiri Pirko
Quoted 3 lines · Tue, Nov 11, 2014 at 04:32:32PM CET, [email protected] wrote:

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Quoted 8 lines

Well, as I said, it is the same as for physical port id. But if needed, there can be added some simple mechanism for the id registration ensuring their uniqueness.

Quoted 2 lines

Even now, multiple rocker instances would have the same ID.

It depends on what hw returns to driver.

I think that falls within the responsibility of the API. I'll propose a patch to address it after this gets in.

#43 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

In reply to Jiri Pirko
Quoted 23 lines · Jiri Pirko
Quoted 22 lines · Tue, Nov 11, 2014 at 04:32:32PM CET, [email protected] wrote:
Quoted 20 lines · Jiri Pirko
Quoted 13 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

Quoted 3 lines

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

This is something similar to physical port id. Each driver should take care of generating that id.

Quoted 7 lines
Quoted 3 lines

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Well, as I said, it is the same as for physical port id. But if needed, there can be added some simple mechanism for the id registration ensuring their uniqueness.

We could use the idr/ida subsystem to provide a global unique id per switch device that gets registered, ultimately, I suspect that a management application might want to get some sense of the topology by exploiting some unique HW properties such as:

- MDIO bus address for MDIO-connected switches
- SPI chip-select address
- GPIO(s) used to connect
- PCI bus/slot

they are also unique by design, and add to that any revision/OUI register that is available for the driver. I can't find of a good way to hash that to produce a unique identifier, but maybe we can use that information somehow.

Quoted 6 lines
Quoted 3 lines

Even now, multiple rocker instances would have the same ID.

It depends on what hw returns to driver.

#44 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

In reply to Thomas Graf
Quoted 16 lines · Thomas Graf
Quoted 15 lines · Jiri Pirko
Quoted 14 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 10 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

Quoted 7 lines
Quoted 2 lines

This is something similar to physical port id. Each driver should take care of generating that id.

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Even now, multiple rocker instances would have the same ID.

yep, that was my concern on the switch id namespace handling (on the other thread).

#45 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

Quoted 20 lines · Roopa Prabhu
Quoted 19 lines · Thomas Graf
Quoted 18 lines · Jiri Pirko
Quoted 12 lines · Tue, Nov 11, 2014 at 03:29:46PM CET, [email protected] wrote:
Quoted 11 lines · John Fastabend

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 6 lines · Jiri Pirko
drivers/net/ethernet/rocker/rocker.c new file +6 -0
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+                    struct netdev_phys_item_id *psid)
+{
+    struct rocker_port *rocker_port = netdev_priv(dev);
+    struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address
should work.

Quoted 3 lines

This needs more work afterwards. Either we define that the switch ID is only unique in combination with the parent ifindex or we need to introduce a notation of uniquness into the switch ID itself.

This is something similar to physical port id. Each driver should take care of generating that id.

Quoted 7 lines
Quoted 5 lines

If the ID is only unique within a driver, then the user space cannot rely on using the ID to group switch ports. Multiple drivers might come up with the same ID.

Even now, multiple rocker instances would have the same ID.

yep, that was my concern on the switch id namespace handling (on the other thread).

At least the devices I work with have a burnt in MAC which could be used for this.

Signature · 1 line
John Fastabend         Intel Corporation
author maintainer
#46 lore raw

Re: [patch net-next v2 05/10] rocker: introduce rocker switch driver

In reply to John Fastabend
Quoted 37 lines · Mon, Nov 10, 2014 at 11:04:26PM CET, [email protected] wrote:
Quoted 23 lines · Jiri Pirko

This patch introduces the first driver to benefit from the switchdev infrastructure and to implement newly introduced switch ndos. This is a driver for emulated switch chip implemented in qemu:
https://github.com/sfeldma/qemu-rocker/

This patch is a result of joint work with Scott Feldman.

---
 MAINTAINERS                          |    7 +
 drivers/net/ethernet/Kconfig         |    1 +
 drivers/net/ethernet/Makefile        |    1 +
 drivers/net/ethernet/rocker/Kconfig  |   27 +
 drivers/net/ethernet/rocker/Makefile |    5 +
 drivers/net/ethernet/rocker/rocker.c | 2060 ++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h |  427 +++++++
 7 files changed, 2528 insertions(+)
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h

[...]

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+
+static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_desc_info *desc_info;
+	struct rocker_tlv *frags;
+	int i;
+	int err;
+
Quoted 8 lines

drivers/net/ethernet/rocker/rocker.c line 1534

Quoted 3 lines
drivers/net/ethernet/rocker/rocker.c new file +3 -0
+	desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+	if (unlikely(!desc_info)) {
+		if (net_ratelimit())

Could you have a netif_stop_queue() here as well same as below? Not that optimizing the xmit routine is the interesting part of this patch. But I guess this is just some strange error path because I see you check this case below.

This code should never be reached.
If the ring is full, the queue is previously stopped by:

        desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
        if (!desc_info)
                netif_stop_queue(dev);
Quoted 136 lines
Quoted 24 lines
drivers/net/ethernet/rocker/rocker.c new file +23 -0
+			netdev_err(dev, "tx ring full when queue awake\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	rocker_desc_cookie_ptr_set(desc_info, skb);
+
+	frags = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAGS);
+	if (!frags)
+		goto out;
+	err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+					  skb->data, skb_headlen(skb));
+	if (err)
+		goto nest_cancel;
+	if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX)
+		goto nest_cancel;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+						  skb_frag_address(frag),
+						  skb_frag_size(frag));
+		if (err)

drivers/net/ethernet/rocker/rocker.c line 1567

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+			goto unmap_frags;
+	}
+	rocker_tlv_nest_end(desc_info, frags);
+
+	rocker_desc_gen_clear(desc_info);
+	rocker_desc_head_set(rocker, &rocker_port->tx_ring, desc_info);
+
+	desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+	if (!desc_info)
+		netif_stop_queue(dev);

I'm not entirely sure I followed the TLV usage here but OK. If it works...

Quoted 24 lines
drivers/net/ethernet/rocker/rocker.c new file +24 -0
+
+	return NETDEV_TX_OK;
+
+unmap_frags:
+	rocker_tx_desc_frags_unmap(rocker_port, desc_info);
+nest_cancel:
+	rocker_tlv_nest_cancel(desc_info, frags);
+out:
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int rocker_port_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	int err;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	err = rocker_cmd_set_port_settings_macaddr(rocker_port, addr->sa_data);
+	if (err)
+		return err;

drivers/net/ethernet/rocker/rocker.c line 1601

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static int rocker_port_sw_parent_id_get(struct net_device *dev,
+					struct netdev_phys_item_id *psid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct rocker *rocker = rocker_port->rocker;
+

hmm looks like you read this out of a magic switch register :) but my switch doesn't have this magic reg. I suposse the switch MAC address should work.

Quoted 37 lines
drivers/net/ethernet/rocker/rocker.c new file +37 -0
+	psid->id_len = sizeof(rocker->hw.id);
+	memcpy(&psid->id, &rocker->hw.id, psid->id_len);
+	return 0;
+}
+
+static const struct net_device_ops rocker_port_netdev_ops = {
+	.ndo_open			= rocker_port_open,
+	.ndo_stop			= rocker_port_stop,
+	.ndo_start_xmit			= rocker_port_xmit,
+	.ndo_set_mac_address		= rocker_port_set_mac_address,
+	.ndo_sw_parent_id_get		= rocker_port_sw_parent_id_get,
+};
+
+/********************
+ * ethtool interface
+ ********************/
+
+static int rocker_port_get_settings(struct net_device *dev,
+				    struct ethtool_cmd *ecmd)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+
+	return rocker_cmd_get_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static int rocker_port_set_settings(struct net_device *dev,
+				    struct ethtool_cmd *ecmd)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+
+	return rocker_cmd_set_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static void rocker_port_get_drvinfo(struct net_device *dev,
+				    struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver));

drivers/net/ethernet/rocker/rocker.c line 1648

Quoted 10 lines
drivers/net/ethernet/rocker/rocker.c new file +10 -0
+	strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static const struct ethtool_ops rocker_port_ethtool_ops = {
+	.get_settings		= rocker_port_get_settings,
+	.set_settings		= rocker_port_set_settings,
+	.get_drvinfo		= rocker_port_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
+

[...]

Looks reasonable to me, although I mostly scanned it and looked over the interface parts. My comments are just observations no need to change anything for them.

Signature · 1 line
John Fastabend         Intel Corporation
author maintainer
#47 lore raw

PATCH v2 6/10 bridge: introduce fdb offloading via switchdev

In reply to Jiri Pirko

From: Scott Feldman <[email protected]>

Add two new ndos: ndo_sw_port_fdb_add/del to offload static bridge fdb entries. Static bridge FDB entries are installed, for example, using iproute2 bridge cmd:

bridge fdb add ADDR dev DEV master vlan VID

This would install ADDR into the bridge's FDB for port DEV on vlan VID. The switch driver implements two ndo_swdev ops to add/delete FDB entries in the switch device:

int ndo_sw_port_fdb_add(struct net_device *dev,
const unsigned char *addr, u16 vid);

int ndo_sw_port_fdb_del(struct net_device *dev,
const unsigned char *addr, u16 vid);

The driver returns 0 on success, negative error code on failure.

Note: the switch driver would not implement ndo_fdb_add/del/dump on a port netdev as these are intended for devices maintaining their own FDB. In our case, we want the Linux bridge to own the FBD.

Note: by default, the bridge does not filter on VLAN and only bridges untagged traffic. To enable VLAN support, turn on VLAN filtering:

echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering

---
 include/linux/netdevice.h | 16 ++++++++++++++++
 include/net/switchdev.h   | 17 +++++++++++++++++
 net/bridge/br_fdb.c       | 10 +++++++++-
 net/switchdev/switchdev.c | 41 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 1 deletion(-)
include/linux/netdevice.h +16 -0
index 97eade9..116a19d 100644
@@ -1023,6 +1023,16 @@ 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_sw_port_fdb_add)(struct net_device *dev,
+ *			      const unsigned char *addr,
+ *			      u16 vid);
+ *	Called to add a fdb to switch device port.
+ *
+ * int (*ndo_sw_port_fdb_del)(struct net_device *dev,
+ *			      const unsigned char *addr,
+ *			      u16 vid);
+ *	Called to delete a fdb from switch device port.
  */
 struct net_device_ops {
 	int			(*ndo_init)(struct net_device *dev);
@@ -1177,6 +1187,12 @@ struct net_device_ops {
 #ifdef CONFIG_NET_SWITCHDEV
 	int			(*ndo_sw_parent_id_get)(struct net_device *dev,
 							struct netdev_phys_item_id *psid);
+	int			(*ndo_sw_port_fdb_add)(struct net_device *dev,
+						       const unsigned char *addr,
+						       u16 vid);
+	int			(*ndo_sw_port_fdb_del)(struct net_device *dev,
+						       const unsigned char *addr,
+						       u16 vid);
 #endif
 };
 
include/net/switchdev.h +17 -0
index 79bf9bd..130cef7 100644
@@ -1,6 +1,7 @@
 /*
  * include/net/switchdev.h - Switch device API
  * Copyright (c) 2014 Jiri Pirko <[email protected]>
+ * Copyright (c) 2014 Scott Feldman <[email protected]>
  *
  * 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
@@ -16,6 +17,10 @@
 
 int netdev_sw_parent_id_get(struct net_device *dev,
 			    struct netdev_phys_item_id *psid);
+int netdev_sw_port_fdb_add(struct net_device *dev,
+			   const unsigned char *addr, u16 vid);
+int netdev_sw_port_fdb_del(struct net_device *dev,
+			   const unsigned char *addr, u16 vid);
 
 #else
 
@@ -25,6 +30,18 @@ static inline int netdev_sw_parent_id_get(struct net_device *dev,
 	return -EOPNOTSUPP;
 }
 
+static inline int netdev_sw_port_fdb_add(struct net_device *dev,
+					 const unsigned char *addr, u16 vid)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int netdev_sw_port_fdb_del(struct net_device *dev,
+					 const unsigned char *addr, u16 vid)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
 
 #endif /* _LINUX_SWITCHDEV_H_ */
net/bridge/br_fdb.c +9 -1
index 6f6c95c..f6f8bb5 100644
@@ -24,6 +24,7 @@
 #include <linux/atomic.h>
 #include <asm/unaligned.h>
 #include <linux/if_vlan.h>
+#include <net/switchdev.h>
 #include "br_private.h"
 
 static struct kmem_cache *br_fdb_cache __read_mostly;
@@ -132,8 +133,12 @@ static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
 
 static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
 {
-	if (f->is_static)
+	if (f->is_static) {
 		fdb_del_hw(br, f->addr.addr);
+		if (f->dst)
+			netdev_sw_port_fdb_del(f->dst->dev,
+					       f->addr.addr, f->vlan_id);
+	}
 
 	hlist_del_rcu(&f->hlist);
 	fdb_notify(br, f, RTM_DELNEIGH);
@@ -755,18 +760,21 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
 				fdb_add_hw(br, addr);
+				netdev_sw_port_fdb_add(source->dev, addr, vid);
 			}
 		} else if (state & NUD_NOARP) {
 			fdb->is_local = 0;
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
 				fdb_add_hw(br, addr);
+				netdev_sw_port_fdb_add(source->dev, addr, vid);
 			}
 		} else {
 			fdb->is_local = 0;
 			if (fdb->is_static) {
 				fdb->is_static = 0;
 				fdb_del_hw(br, addr);
+				netdev_sw_port_fdb_del(source->dev, addr, vid);
 			}
 		}
 
net/switchdev/switchdev.c +41 -0

50 lines not on this page · raw message

Signature · 1 line
1.9.3
#48 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 22 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add two new ndos: ndo_sw_port_fdb_add/del to offload static bridge fdb entries. Static bridge FDB entries are installed, for example, using iproute2 bridge cmd:

bridge fdb add ADDR dev DEV master vlan VID

This would install ADDR into the bridge's FDB for port DEV on vlan VID. The switch driver implements two ndo_swdev ops to add/delete FDB entries in the switch device:

int ndo_sw_port_fdb_add(struct net_device *dev,
const unsigned char *addr, u16 vid);

int ndo_sw_port_fdb_del(struct net_device *dev,
const unsigned char *addr, u16 vid);

The driver returns 0 on success, negative error code on failure.

Quoted 9 lines

Note: the switch driver would not implement ndo_fdb_add/del/dump on a port netdev as these are intended for devices maintaining their own FDB. In our case, we want the Linux bridge to own the FBD.

Note: by default, the bridge does not filter on VLAN and only bridges untagged traffic. To enable VLAN support, turn on VLAN filtering:

echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering

Sorry - why is the current fdb_add/del insufficient? It needs a vlanid and the master/self flags should indicate intent to add to h/w vs s/w.

cheers,
jamal

author maintainer
#49 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 27 lines · Mon, Nov 10, 2014 at 04:47:48AM CET, [email protected] wrote:
Quoted 26 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add two new ndos: ndo_sw_port_fdb_add/del to offload static bridge fdb entries. Static bridge FDB entries are installed, for example, using iproute2 bridge cmd:

bridge fdb add ADDR dev DEV master vlan VID

This would install ADDR into the bridge's FDB for port DEV on vlan VID. The switch driver implements two ndo_swdev ops to add/delete FDB entries in the switch device:

int ndo_sw_port_fdb_add(struct net_device *dev,
const unsigned char *addr, u16 vid);

int ndo_sw_port_fdb_del(struct net_device *dev,
const unsigned char *addr, u16 vid);

The driver returns 0 on success, negative error code on failure.

Note: the switch driver would not implement ndo_fdb_add/del/dump on a port netdev as these are intended for devices maintaining their own FDB. In our case, we want the Linux bridge to own the FBD.

Quoted 8 lines
Quoted 5 lines

Note: by default, the bridge does not filter on VLAN and only bridges untagged traffic. To enable VLAN support, turn on VLAN filtering:

echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering

Sorry - why is the current fdb_add/del insufficient? It needs a vlanid and the master/self flags should indicate intent to add to h/w vs s/w.

Jamal, I believe we discussed this already. The thing is that current fdb_add/del does not need vlanid and master/self flags, because it already has that (struct nlattr *tb[]). Here is the whole list of parameters to these functions:
NDA_DST,
NDA_LLADDR,
NDA_CACHEINFO,
NDA_PROBES,
NDA_VLAN,
NDA_PORT,
NDA_VNI,
NDA_IFINDEX,
NDA_MASTER,

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Scott, you may probably want to add something to this.

Quoted 4 lines

cheers,
jamal

#50 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 61 lines · Jiri Pirko
Quoted 27 lines · Mon, Nov 10, 2014 at 04:47:48AM CET, [email protected] wrote:
Quoted 26 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add two new ndos: ndo_sw_port_fdb_add/del to offload static bridge fdb entries. Static bridge FDB entries are installed, for example, using iproute2 bridge cmd:

bridge fdb add ADDR dev DEV master vlan VID

This would install ADDR into the bridge's FDB for port DEV on vlan VID. The switch driver implements two ndo_swdev ops to add/delete FDB entries in the switch device:

int ndo_sw_port_fdb_add(struct net_device *dev,
const unsigned char *addr, u16 vid);

int ndo_sw_port_fdb_del(struct net_device *dev,
const unsigned char *addr, u16 vid);

The driver returns 0 on success, negative error code on failure.

Note: the switch driver would not implement ndo_fdb_add/del/dump on a port netdev as these are intended for devices maintaining their own FDB. In our case, we want the Linux bridge to own the FBD.

Quoted 8 lines
Quoted 5 lines

Note: by default, the bridge does not filter on VLAN and only bridges untagged traffic. To enable VLAN support, turn on VLAN filtering:

echo 1 >/sys/class/net/<bridge>/bridge/vlan_filtering

Sorry - why is the current fdb_add/del insufficient? It needs a vlanid and the master/self flags should indicate intent to add to h/w vs s/w.

Jamal, I believe we discussed this already. The thing is that current fdb_add/del does not need vlanid and master/self flags, because it already has that (struct nlattr *tb[]). Here is the whole list of parameters to these functions:
NDA_DST,
NDA_LLADDR,
NDA_CACHEINFO,
NDA_PROBES,
NDA_VLAN,
NDA_PORT,
NDA_VNI,
NDA_IFINDEX,
NDA_MASTER,

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Quoted 1 line

Scott, you may probably want to add something to this.

You hit the main point: having to synthesize netlink msg in the bridge driver and pass it down to port driver using .ndo_fdb_add/del is awkward. And then, if the port driver implements .ndo_fdb_add/del (and dump), then user could by-pass bridge and install fdbs directly on port, as if the port maintains its own fdb. We want the bridge fdb to be the single fdb, and static fdbs installed by user on bridge to be pushed down to sw port driver to be installed in hw.

Quoted 4 lines
Quoted 4 lines

cheers,
jamal

#51 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

In reply to Jiri Pirko
Quoted 6 lines · Jiri Pirko
Quoted 3 lines · Mon, Nov 10, 2014 at 04:47:48AM CET, [email protected] wrote:
Quoted 2 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Jamal, I believe we discussed this already.

I cant remember how that ended.

Quoted 14 lines

The thing is that current
fdb_add/del does not need vlanid and master/self flags, because it already has that (struct nlattr *tb[]). Here is the whole list of parameters to these functions:
NDA_DST,
NDA_LLADDR,
NDA_CACHEINFO,
NDA_PROBES,
NDA_VLAN,
NDA_PORT,
NDA_VNI,
NDA_IFINDEX,
NDA_MASTER,

Quoted 3 lines

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.

Trying to understand.

A netlink message for a bridge to add an fdb is targeted at the *bridge port*.
That message has semantic which says "please add this entry to the software bridge and/or offloaded hardware".
If something is targetted at the bridge port, ->ndo_fdb_add() is invoked with an internally chewed structure.
Why would you have to construct a new netlink message to the driver?

Quoted 2 lines

As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else.

I am still missing understanding that part.
Or maybe are you saying that you dont want to pass netlink constructs to the driver?

Quoted 6 lines

See vxlan code for
what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Ok, now a small spark ignited in my brain. You did talk about renaming things to neighXXX in one of the exchanges. I think this is a separate issue from the question of why you cant refactor ndo_fdb_add/del

The abuse of using this interface for unicast addresses is probably driven by the fact some of the hardware probably offloads vlanid 0 or something speacial like 4095 to point to the underlying hardware that "this belongs to host cpu".
I am not a fan of it (and have posted in exchanges with Vlad in the past).

cheers,
jamal

author maintainer
#52 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 30 lines · Mon, Nov 10, 2014 at 01:47:33PM CET, [email protected] wrote:
Quoted 6 lines · Jiri Pirko
Quoted 3 lines · Mon, Nov 10, 2014 at 04:47:48AM CET, [email protected] wrote:
Quoted 2 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Jamal, I believe we discussed this already.

I cant remember how that ended.

Quoted 14 lines

The thing is that current
fdb_add/del does not need vlanid and master/self flags, because it already has that (struct nlattr *tb[]). Here is the whole list of parameters to these functions:
NDA_DST,
NDA_LLADDR,
NDA_CACHEINFO,
NDA_PROBES,
NDA_VLAN,
NDA_PORT,
NDA_VNI,
NDA_IFINDEX,
NDA_MASTER,

Quoted 3 lines

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.

Trying to understand.

Quoted 7 lines

A netlink message for a bridge to add an fdb is targeted at the *bridge port*.
That message has semantic which says "please add this entry to the software bridge and/or offloaded hardware".
If something is targetted at the bridge port, ->ndo_fdb_add() is invoked with an internally chewed structure.
Why would you have to construct a new netlink message to the driver?

Because now, If you would like to pass one of NDA_DST, NDA_LLADDR, NDA_CACHEINFO, NDA_PROBES, NDA_VLAN, NDA_PORT, NDA_VNI, NDA_IFINDEX, NDA_MASTER values via ndo_fdb_add/del to the driver, you have to construct "struct nlattr *tb[]". Preprocessing this tb into struct might be suitable for some use-case, for some it may not.

Quoted 8 lines
Quoted 4 lines

As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else.

I am still missing understanding that part.
Or maybe are you saying that you dont want to pass netlink constructs to the driver?

What I try to say is that the naming ndo_fdb_add/del is not accurate because it is now used for far more than fdb (addr, vlan). See vxlan code for example.

Quoted 11 lines
Quoted 7 lines

See vxlan code for
what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Ok, now a small spark ignited in my brain. You did talk about renaming things to neighXXX in one of the exchanges. I think this is a separate issue from the question of why you cant refactor ndo_fdb_add/del

It can be probably refactored in a way so it fits our fdb offloading needs. I'm not really sure we would want it. ndo_fdb_* use-case is dirrerent from what we introduce with ndo_sw_port_fdb_*. The only similarity is the "fdb" name which in case of ndo_fdb_* is no longer correct I believe.

Quoted 10 lines

The abuse of using this interface for unicast addresses is probably driven by the fact some of the hardware probably offloads vlanid 0 or something speacial like 4095 to point to the underlying hardware that "this belongs to host cpu".
I am not a fan of it (and have posted in exchanges with Vlad in the past).

cheers,
jamal

#53 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 9 lines · Jiri Pirko

Mon, Nov 10, 2014 at 01:47:33PM CET, [email protected] wrote:

Because now, If you would like to pass one of NDA_DST, NDA_LLADDR, NDA_CACHEINFO, NDA_PROBES, NDA_VLAN, NDA_PORT, NDA_VNI, NDA_IFINDEX, NDA_MASTER values via ndo_fdb_add/del to the driver, you have to construct "struct nlattr *tb[]". Preprocessing this tb into struct might be suitable for some use-case, for some it may not.

Ok, I see what you mean now. yes, netlink attributes are passed around.

Quoted 5 lines

What I try to say is that the naming ndo_fdb_add/del is not accurate because it is now used for far more than fdb (addr, vlan). See vxlan code for example.

In vxlan semantics that is an "fdb".
In any case, I am indifferent to be honest - netlink attributes in this case seem to be easier. i.e For the driver:
Ignore what you dont want and suck in what you need (whether vxlan or vlan or nvgre etc).

cheers,
jamal

#54 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

In reply to Jiri Pirko
Quoted 9 lines · Jiri Pirko

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Can you elaborate a bit on the intended semantic differences between the existing ndo_fdb_add() and ndo_sw_port_fdb_add()? I'm not sure we need the sw_ prefix for this specific ndo.

I completely agree that relying on Netlink is wrong because we'll have in-kernel users of the API but I believe that existing ndo_fdb_add() implementations in i40e, ixgbe, qlcnic and macvlan could use the new API you propose.

How about we rename the existing ndo_fdb_add() to ndo_neigh_add() as you propose and convert vxlan over to it and have all others which don't even depend on the Netlink attributes being passed in (i40e, ixgbe, qlcnic, macvlan) use ndo_fdb_add() which would have the behaviour of your proposed ndo_sw_port_fdb_add()?

#55 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 11 lines · Thomas Graf
Quoted 9 lines · Jiri Pirko

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Quoted 8 lines

Can you elaborate a bit on the intended semantic differences between the existing ndo_fdb_add() and ndo_sw_port_fdb_add()? I'm not sure we need the sw_ prefix for this specific ndo.

I completely agree that relying on Netlink is wrong because we'll have in-kernel users of the API but I believe that existing ndo_fdb_add() implementations in i40e, ixgbe, qlcnic and macvlan could use the new API you propose.

I also think the same API could be used quite easily on the current drivers that use it.

I was looking at this earlier today and there are only 5 drivers (outside the bridge code) that support ndo_fdb_add. The 3 hardware drivers and vxlan driver seem like they could use this new API. The macvlan code appears to simply set the uc and mc lists, which seems like it could be done other ways -- confirmation from John Fastabend, Roopa, and mst would be good.

Quoted 5 lines

How about we rename the existing ndo_fdb_add() to ndo_neigh_add() as you propose and convert vxlan over to it and have all others which don't even depend on the Netlink attributes being passed in (i40e, ixgbe, qlcnic, macvlan) use ndo_fdb_add() which would have the behaviour of your proposed ndo_sw_port_fdb_add()?

I would much rather see something like Thomas proposes here. I know you would like to see these patches get included (I'm anxious to see better in-kernel offload support too!), but separate, possibly unnecessary APIs like this can get painful for driver maintainers (upstream and distro maintainers).

#56 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 22 lines · Andy Gospodarek
Quoted 10 lines · Thomas Graf
Quoted 9 lines · Jiri Pirko

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Quoted 8 lines

Can you elaborate a bit on the intended semantic differences between the existing ndo_fdb_add() and ndo_sw_port_fdb_add()? I'm not sure we need the sw_ prefix for this specific ndo.

I completely agree that relying on Netlink is wrong because we'll have in-kernel users of the API but I believe that existing ndo_fdb_add() implementations in i40e, ixgbe, qlcnic and macvlan could use the new API you propose.

I also think the same API could be used quite easily on the current drivers that use it.

Quoted 6 lines

I was looking at this earlier today and there are only 5 drivers (outside the bridge code) that support ndo_fdb_add. The 3 hardware drivers and vxlan driver seem like they could use this new API. The macvlan code appears to simply set the uc and mc lists, which seems like it could be done other ways -- confirmation from John Fastabend, Roopa, and mst would be good.

yes, that is correct. The macvlan code, when not set for passthru mode, seems to just program the uc-mc lists,
which again get synched to the lowerdev (and possibly from lowerdev to
hw in some cases).

I agree that it would be really nice if the existing api's can be made to work.

Quoted 11 lines
Quoted 5 lines

How about we rename the existing ndo_fdb_add() to ndo_neigh_add() as you propose and convert vxlan over to it and have all others which don't even depend on the Netlink attributes being passed in (i40e, ixgbe, qlcnic, macvlan) use ndo_fdb_add() which would have the behaviour of your proposed ndo_sw_port_fdb_add()?

I would much rather see something like Thomas proposes here. I know you would like to see these patches get included (I'm anxious to see better in-kernel offload support too!), but separate, possibly unnecessary APIs like this can get painful for driver maintainers (upstream and distro maintainers).

Ack!.

author maintainer
#57 lore raw

Re: [patch net-next v2 06/10] bridge: introduce fdb offloading via switchdev

Quoted 23 lines · Mon, Nov 10, 2014 at 08:03:41PM CET, [email protected] wrote:
Quoted 22 lines · Andy Gospodarek
Quoted 10 lines · Thomas Graf
Quoted 9 lines · Jiri Pirko

There are few problems in re-using this. It is netlink based so for calling it from bridge code, we would have to construct netlink message. But that could be probably changed.
As you can see from the list of parameters, this is no longer about fdb (addr, vlanid) but this has been extended to something else. See vxlan code for what this is used for. I believe that fdb_add/del should be renamed to something else, perhaps l2neigh_add/del or something like that. The other problem is that fdb_add/del is currently used by various drivers for different purpose (adding macs to unicast list).

Quoted 8 lines

Can you elaborate a bit on the intended semantic differences between the existing ndo_fdb_add() and ndo_sw_port_fdb_add()? I'm not sure we need the sw_ prefix for this specific ndo.

I completely agree that relying on Netlink is wrong because we'll have in-kernel users of the API but I believe that existing ndo_fdb_add() implementations in i40e, ixgbe, qlcnic and macvlan could use the new API you propose.

I also think the same API could be used quite easily on the current drivers that use it.

Quoted 8 lines
Quoted 6 lines

I was looking at this earlier today and there are only 5 drivers (outside the bridge code) that support ndo_fdb_add. The 3 hardware drivers and vxlan driver seem like they could use this new API. The macvlan code appears to simply set the uc and mc lists, which seems like it could be done other ways -- confirmation from John Fastabend, Roopa, and mst would be good.

yes, that is correct. The macvlan code, when not set for passthru mode, seems to just program the uc-mc lists,

If you look at how drivers implement this, they also only add addr into uc/mc list. And if the ndo fdb add is not implemented by the driver, core does it for you - see ndo_dflt_fdb_add.

Quoted 10 lines

which again get synched to the lowerdev (and possibly from lowerdev to hw in some cases).

I agree that it would be really nice if the existing api's can be made to work.

Quoted 5 lines
Quoted 5 lines

How about we rename the existing ndo_fdb_add() to ndo_neigh_add() as you propose and convert vxlan over to it and have all others which don't even depend on the Netlink attributes being passed in (i40e, ixgbe, qlcnic, macvlan) use ndo_fdb_add() which would have the behaviour of your proposed ndo_sw_port_fdb_add()?

Quoted 7 lines
Quoted 6 lines

I would much rather see something like Thomas proposes here. I know you would like to see these patches get included (I'm anxious to see better in-kernel offload support too!), but separate, possibly unnecessary APIs like this can get painful for driver maintainers (upstream and distro maintainers).

Ack!.

I will think about this more and prepare something like Thomas proposes. Stay tuned, I will be out undil Monday so I will post v3 Tue/Wed next week.

In the meantime, feel free to study the fdb_add code and feel free to give me some more thoughts/patches about this. Thanks!

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

author maintainer
#58 lore raw

PATCH v2 7/10 bridge: call netdev_sw_port_stp_update when bridge port STP status changes

In reply to Jiri Pirko

From: Scott Feldman <[email protected]>

To notify switch driver of change in STP state of bridge port, add new .ndo op and provide swdev wrapper func to call ndo op. Use it in bridge code then.

---
 include/linux/netdevice.h |  6 ++++++
 include/net/switchdev.h   |  6 ++++++
 net/bridge/br_netlink.c   |  2 ++
 net/bridge/br_stp.c       |  4 ++++
 net/bridge/br_stp_if.c    |  3 +++
 net/bridge/br_stp_timer.c |  2 ++
 net/switchdev/switchdev.c | 19 +++++++++++++++++++
 7 files changed, 42 insertions(+)
include/linux/netdevice.h +6 -0
index 116a19d..35f21a95 100644
@@ -1033,6 +1033,10 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *			      const unsigned char *addr,
  *			      u16 vid);
  *	Called to delete a fdb from switch device port.
+ *
+ * int (*ndo_sw_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);
@@ -1193,6 +1197,8 @@ struct net_device_ops {
 	int			(*ndo_sw_port_fdb_del)(struct net_device *dev,
 						       const unsigned char *addr,
 						       u16 vid);
+	int			(*ndo_sw_port_stp_update)(struct net_device *dev,
+							  u8 state);
 #endif
 };
 
include/net/switchdev.h +6 -0
index 130cef7..bbf7369 100644
@@ -21,6 +21,7 @@ int netdev_sw_port_fdb_add(struct net_device *dev,
 			   const unsigned char *addr, u16 vid);
 int netdev_sw_port_fdb_del(struct net_device *dev,
 			   const unsigned char *addr, u16 vid);
+int netdev_sw_port_stp_update(struct net_device *dev, u8 state);
 
 #else
 
@@ -42,6 +43,11 @@ static inline int netdev_sw_port_fdb_del(struct net_device *dev,
 	return -EOPNOTSUPP;
 }
 
+static inline int netdev_sw_port_stp_update(struct net_device *dev, u8 state)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
 
 #endif /* _LINUX_SWITCHDEV_H_ */
net/bridge/br_netlink.c +2 -0
index 86c239b..13fecf1 100644
@@ -17,6 +17,7 @@
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <uapi/linux/if_bridge.h>
+#include <net/switchdev.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -304,6 +305,7 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state)
 
 	br_set_state(p, state);
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_port_state_selection(p->br);
 	return 0;
 }
net/bridge/br_stp.c +4 -0
index 2b047bc..c00139b 100644
@@ -12,6 +12,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/rculist.h>
+#include <net/switchdev.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -114,6 +115,7 @@ static void br_root_port_block(const struct net_bridge *br,
 
 	br_set_state(p, BR_STATE_LISTENING);
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_ifinfo_notify(RTM_NEWLINK, p);
 
 	if (br->forward_delay > 0)
@@ -394,6 +396,7 @@ static void br_make_blocking(struct net_bridge_port *p)
 
 		br_set_state(p, BR_STATE_BLOCKING);
 		br_log_state(p);
+		netdev_sw_port_stp_update(p->dev, p->state);
 		br_ifinfo_notify(RTM_NEWLINK, p);
 
 		del_timer(&p->forward_delay_timer);
@@ -419,6 +422,7 @@ static void br_make_forwarding(struct net_bridge_port *p)
 
 	br_multicast_enable_port(p);
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_ifinfo_notify(RTM_NEWLINK, p);
 
 	if (br->forward_delay != 0)
net/bridge/br_stp_if.c +3 -0
index 4114687..91279f8 100644
@@ -15,6 +15,7 @@
 #include <linux/kmod.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
+#include <net/switchdev.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -89,6 +90,7 @@ void br_stp_enable_port(struct net_bridge_port *p)
 	br_init_port(p);
 	br_port_state_selection(p->br);
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_ifinfo_notify(RTM_NEWLINK, p);
 }
 
@@ -105,6 +107,7 @@ void br_stp_disable_port(struct net_bridge_port *p)
 	p->config_pending = 0;
 
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_ifinfo_notify(RTM_NEWLINK, p);
 
 	del_timer(&p->message_age_timer);
net/bridge/br_stp_timer.c +2 -0
index 4fcaa67..5bb8997 100644
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/times.h>
+#include <net/switchdev.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -97,6 +98,7 @@ static void br_forward_delay_timer_expired(unsigned long arg)
 		netif_carrier_on(br->dev);
 	}
 	br_log_state(p);
+	netdev_sw_port_stp_update(p->dev, p->state);
 	br_ifinfo_notify(RTM_NEWLINK, p);
 	spin_unlock(&br->lock);
 }
net/switchdev/switchdev.c +19 -0
index 93d47b7..75997a5 100644
@@ -72,3 +72,22 @@ int netdev_sw_port_fdb_del(struct net_device *dev,
 	return ops->ndo_sw_port_fdb_del(dev, addr, vid);
 }
 EXPORT_SYMBOL(netdev_sw_port_fdb_del);
+
+/**
+ *	netdev_sw_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_sw_port_stp_update(struct net_device *dev, u8 state)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+
+	if (!ops->ndo_sw_port_stp_update)
+		return -EOPNOTSUPP;
+	WARN_ON(!ops->ndo_sw_parent_id_get);
+	return ops->ndo_sw_port_stp_update(dev, state);
+}
+EXPORT_SYMBOL(netdev_sw_port_stp_update);
Signature · 1 line
1.9.3
#59 lore raw

Re: [patch net-next v2 07/10] bridge: call netdev_sw_port_stp_update when bridge port STP status changes

Quoted 23 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

To notify switch driver of change in STP state of bridge port, add new .ndo op and provide swdev wrapper func to call ndo op. Use it in bridge code then.

---
  include/linux/netdevice.h |  6 ++++++
  include/net/switchdev.h   |  6 ++++++
  net/bridge/br_netlink.c   |  2 ++
  net/bridge/br_stp.c       |  4 ++++
  net/bridge/br_stp_if.c    |  3 +++
  net/bridge/br_stp_timer.c |  2 ++
  net/switchdev/switchdev.c | 19 +++++++++++++++++++
  7 files changed, 42 insertions(+)
include/linux/netdevice.h +0 -0
index 116a19d..35f21a95 100644

include/linux/netdevice.h typedef u16 (*select_queue_fallback_t)(struct net_device *dev, · line 1039

Quoted 7 lines
include/linux/netdevice.h +4 -0
@@ -1033,6 +1033,10 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
   *			      const unsigned char *addr,
   *			      u16 vid);
   *	Called to delete a fdb from switch device port.
+ *
+ * int (*ndo_sw_port_stp_update)(struct net_device *dev, u8 state);
+ *	Called to notify switch device port of bridge port STP
+ *	state change.

You are unconditionally calling netdev_sw_port_stp_update(p->dev, p->state);
Again issue is policy. Could you make this work the same way the fdb_add e.g user intent of whether i want to turn a port in hardware and/or software to disabled/learning/etc is reflected?

btw: does _sw_ stand for switch? why not _hw_ ?
Could we have one ndo for all flags instead of individual ones.

I know the current user space code uses u8 as a bitflag; but maybe we can introduce a new u32 flag bitmask that has all the flags set for backward compat? I can count about a total of 10.

cheers,
jamal

#60 lore raw

Re: [patch net-next v2 07/10] bridge: call netdev_sw_port_stp_update when bridge port STP status changes

Quoted 6 lines · Jamal Hadi Salim

You are unconditionally calling netdev_sw_port_stp_update(p->dev, p->state);
Again issue is policy. Could you make this work the same way the fdb_add e.g user intent of whether i want to turn a port in hardware and/or software to disabled/learning/etc is reflected?

Agreed. Can be added in a next series perhaps?

Quoted 6 lines

btw: does _sw_ stand for switch? why not _hw_ ?
Could we have one ndo for all flags instead of individual ones.

I know the current user space code uses u8 as a bitflag; but maybe we can introduce a new u32 flag bitmask that has all the flags set for backward compat? I can count about a total of 10.

I think we can just extend the size of IFLA_BRPORT_STATE, accept both a u8 and u32, and return a u32 that that is compatible to existing u8 readers.

#61 lore raw

Re: [patch net-next v2 07/10] bridge: call netdev_sw_port_stp_update when bridge port STP status changes

Quoted 10 lines · Thomas Graf
Quoted 6 lines · Jamal Hadi Salim

You are unconditionally calling netdev_sw_port_stp_update(p->dev, p->state);
Again issue is policy. Could you make this work the same way the fdb_add e.g user intent of whether i want to turn a port in hardware and/or software to disabled/learning/etc is reflected?

Agreed. Can be added in a next series perhaps?

Doesnt seem be hard to fix now. As Andy was pointing out, we have the opportunity to get the basics right in the beggining.

Quoted 4 lines

I think we can just extend the size of IFLA_BRPORT_STATE, accept both a u8 and u32, and return a u32 that that is compatible to existing u8 readers.

Iam thinking we have an opportunity for a totally different new attribute instead of growing IFLA_BRPORT_STATE to add another bit. Almost every single u8 that is being carried today in its own attribute in the bridge code is in fact a boolean (0/1). We could leave just intro IFLA_BRIDGE_FLAGS and use it for both FDB and BRPORT.

cheers,
jamal

#62 lore raw

Re: [patch net-next v2 07/10] bridge: call netdev_sw_port_stp_update when bridge port STP status changes

In reply to Jamal Hadi Salim
Quoted 40 lines · Jamal Hadi Salim
Quoted 23 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

To notify switch driver of change in STP state of bridge port, add new .ndo op and provide swdev wrapper func to call ndo op. Use it in bridge code then.

---
  include/linux/netdevice.h |  6 ++++++
  include/net/switchdev.h   |  6 ++++++
  net/bridge/br_netlink.c   |  2 ++
  net/bridge/br_stp.c       |  4 ++++
  net/bridge/br_stp_if.c    |  3 +++
  net/bridge/br_stp_timer.c |  2 ++
  net/switchdev/switchdev.c | 19 +++++++++++++++++++
  7 files changed, 42 insertions(+)
include/linux/netdevice.h +0 -0
index 116a19d..35f21a95 100644

include/linux/netdevice.h typedef u16 (*select_queue_fallback_t)(struct · line 1040

Quoted 8 lines
include/linux/netdevice.h +4 -0
@@ -1033,6 +1033,10 @@ typedef u16 (*select_queue_fallback_t)(struct 
 net_device *dev,
   *                  const unsigned char *addr,
   *                  u16 vid);
   *    Called to delete a fdb from switch device port.
+ *
+ * int (*ndo_sw_port_stp_update)(struct net_device *dev, u8 state);
+ *    Called to notify switch device port of bridge port STP
+ *    state change.

You are unconditionally calling netdev_sw_port_stp_update(p->dev, p->state);
Again issue is policy. Could you make this work the same way the fdb_add e.g user intent of whether i want to turn a port in hardware and/or software to disabled/learning/etc is reflected?

Quoted 2 lines

btw: does _sw_ stand for switch? why not _hw_ ?
Could we have one ndo for all flags instead of individual ones.

I agree. There is the bridge port state and a bunch of bridge port flags. A generic ndo will be good.

Quoted 4 lines

I know the current user space code uses u8 as a bitflag; but maybe we can introduce a new u32 flag bitmask that has all the flags set for backward compat? I can count about a total of 10.

author maintainer
#63 lore raw

PATCH v2 8/10 bridge: add API to notify bridge driver of learned FBD on offloaded device

In reply to Jiri Pirko

From: Scott Feldman <[email protected]>

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] <mac> dev <dev> vid <vlan id> master

This patch needs some extra eyeballs for review, in paricular around the locking and contexts.

---
 include/linux/if_bridge.h | 18 ++++++++++
 net/bridge/br_fdb.c       | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+)
include/linux/if_bridge.h +18 -0
index 808dcb8..27ab217 100644
@@ -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_learn_add(struct net_device *dev,
+		     const unsigned char *addr, u16 vid);
+int br_fdb_learn_del(struct net_device *dev,
+		     const unsigned char *addr, u16 vid);
+#else
+static inline int br_fdb_learn_add(struct net_device *dev,
+				   const unsigned char *addr, u16 vid)
+{
+	return 0;
+}
+static inline int br_fdb_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);
net/bridge/br_fdb.c +84 -0

87 lines not on this page · raw message

Signature · 1 line
1.9.3
#64 lore raw

Re: [patch net-next v2 08/10] bridge: add API to notify bridge driver of learned FBD on offloaded device

Quoted 10 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

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).

Quoted 6 lines

This is equivalent to the device running these cmds:

bridge fdb [add|del] <mac> dev <dev> vid <vlan id> master

This patch needs some extra eyeballs for review, in paricular around the locking and contexts.

scott/jiri, love that you have handled this case!, This will be useful.
But, quick question, Cant this also be done using the same ndo_op that is done to add the static fdb..?

Thanks!.

Quoted 129 lines
---
  include/linux/if_bridge.h | 18 ++++++++++
  net/bridge/br_fdb.c       | 84 +++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 102 insertions(+)
include/linux/if_bridge.h +18 -0
index 808dcb8..27ab217 100644
@@ -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_learn_add(struct net_device *dev,
+		     const unsigned char *addr, u16 vid);
+int br_fdb_learn_del(struct net_device *dev,
+		     const unsigned char *addr, u16 vid);
+#else
+static inline int br_fdb_learn_add(struct net_device *dev,
+				   const unsigned char *addr, u16 vid)
+{
+	return 0;
+}
+static inline int br_fdb_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);
net/bridge/br_fdb.c +84 -0
index f6f8bb5..e02d21b 100644
@@ -1022,3 +1022,87 @@ void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p)
  		}
  	}
  }
+
+int br_fdb_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 == NULL) {
+		pr_info("bridge: %s not a bridge port\n", dev->name);
+		err = -EINVAL;
+		goto err_rtnl_unlock;
+	}
+
+	br = p->br;
+
+	spin_lock(&br->hash_lock);
+
+	head = &br->hash[br_mac_hash(addr, vid)];
+	fdb = fdb_find(head, addr, vid);
+	if (fdb == NULL) {
+		fdb = fdb_create(head, p, addr, vid);
+		if (!fdb) {
+			err = -ENOMEM;
+			goto err_unlock;
+		}
+		fdb->is_local = 1;
+		fdb->used = jiffies;
+		fdb->updated = jiffies;
+		fdb_notify(br, fdb, RTM_NEWNEIGH);
+	} else {
+		err = -EEXIST;
+	}
+
+err_unlock:
+	spin_unlock(&br->hash_lock);
+err_rtnl_unlock:
+	rtnl_unlock();
+
+	return err;
+}
+EXPORT_SYMBOL(br_fdb_learn_add);
+
+int br_fdb_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 == NULL) {
+		pr_info("bridge: %s not a bridge port\n", dev->name);
+		err = -EINVAL;
+		goto err_rtnl_unlock;
+	}
+
+	br = p->br;
+
+	spin_lock(&br->hash_lock);
+
+	head = &br->hash[br_mac_hash(addr, vid)];
+	fdb = fdb_find(head, addr, vid);
+	if (fdb)
+		fdb_delete(br, fdb);
+	else
+		err = -ENOENT;
+
+	spin_unlock(&br->hash_lock);
+err_rtnl_unlock:
+	rtnl_unlock();
+
+	return err;
+}
+EXPORT_SYMBOL(br_fdb_learn_del);
#65 lore raw

Re: [patch net-next v2 08/10] bridge: add API to notify bridge driver of learned FBD on offloaded device

Quoted 19 lines · Roopa Prabhu
Quoted 18 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

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] <mac> dev <dev> vid <vlan id> master

Quoted 7 lines
Quoted 2 lines

This patch needs some extra eyeballs for review, in paricular around the locking and contexts.

scott/jiri, love that you have handled this case!, This will be useful. But, quick question, Cant this also be done using the same ndo_op that is done to add the static fdb..?

Maybe. I think I tried sending netlink msg from swdev driver to bridge driver, but wasn't able to make it to work. I'm not sure if it's possible to do that, in general, send netlink kernel-to-kernel. The other option is to synthesize a netlink msg with needed attrs and call ndo in bridge directly. That feels a little yucky to me.

#66 lore raw

Re: [patch net-next v2 08/10] bridge: add API to notify bridge driver of learned FBD on offloaded device

Quoted 22 lines · Scott Feldman
Quoted 21 lines · Roopa Prabhu
Quoted 19 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

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] <mac> dev <dev> vid <vlan id> master

This patch needs some extra eyeballs for review, in paricular around the locking and contexts.

Quoted 8 lines
Quoted 3 lines

scott/jiri, love that you have handled this case!, This will be useful. But, quick question, Cant this also be done using the same ndo_op that is done to add the static fdb..?

Maybe. I think I tried sending netlink msg from swdev driver to bridge driver, but wasn't able to make it to work. I'm not sure if it's possible to do that, in general, send netlink kernel-to-kernel. The other option is to synthesize a netlink msg with needed attrs and call ndo in bridge directly. That feels a little yucky to me.

ok.
If i understand correctly this is just an api that drivers can use if they want to push learnt fdb
entries to the fdb associated with the bridge. So, the learn sync-hw-fdb behavior is switch driver dependent. If the switch driver allows learning on a port, she can use this api to sync learnt entries to the kernel.

How do the policy flags (That jamal and you were discussing on the other thread) apply here ? SYNC_HW_FDB ?...will this flag be needed...?. I am just trying to see how this api relates to the other thread.

Thanks,
Roopa

author maintainer
#67 lore raw

PATCH v2 9/10 rocker: implement rocker ofdpa flow table manipulation

In reply to Jiri Pirko

From: Scott Feldman <[email protected]>

The rocker driver maintains 4 hash tables: flows, groups, FDB, and VLANs.

Flow and group tables track the entries installed to OF-DPA tables, per the OF-DPA spec. See OF-DPA spec for full description of fields in each flow and group table. New table entries are pushed to the device with ADD cmd. Updated entries are pushed to the device with MOD cmd. For flow table entries, a crc32 key is made from fields of the particular field. For group table entries, the group_id is used as the key.

The FDB table tracks fdb entries learned by the device or manually pushed to the bridge by the user. A crc32 key is made from the port/mac/vlan tuple for the fdb entry.

The VLAN table tracks the ifindex-to-internal-vlan mapping for untagged pkts. On ingress, an untagged pkt is inserted with an internal VLAN ID based on the input port's current internal VLAN ID. The input port's internal VLAN will either be referenced by the port's ifindex, if not bridged, or the containing bridge's ifindex, if bridged. Since the ifindex space isn't within a fixed range, uses a hash table (with ifindex as key) to track internal VLAN ID for a given ifindex. The internal VLAN ID range is fixed and currently uses the upper 255 VLAN IDs, starting at 0xf00.

---
 drivers/net/ethernet/rocker/rocker.c | 1468 +++++++++++++++++++++++++++++++++-
 1 file changed, 1466 insertions(+), 2 deletions(-)
drivers/net/ethernet/rocker/rocker.c +1466 -2
index ebad09c..ea58a4f 100644
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/spinlock.h>
+#include <linux/hashtable.h>
 #include <linux/crc32.h>
 #include <linux/sort.h>
 #include <linux/random.h>
@@ -27,6 +28,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/bitops.h>
 #include <net/switchdev.h>
 #include <net/rtnetlink.h>
 #include <asm-generic/io-64-nonatomic-lo-hi.h>
@@ -41,6 +43,123 @@ static const struct pci_device_id rocker_pci_id_table[] = {
 	{0, }
 };
 
+struct rocker_flow_tbl_key {
+	u32 priority;
+	enum rocker_of_dpa_table_id tbl_id;
+	union {
+		struct {
+			u32 in_lport;
+			u32 in_lport_mask;
+			enum rocker_of_dpa_table_id goto_tbl;
+		} ig_port;
+		struct {
+			u32 in_lport;
+			__be16 vlan_id;
+			__be16 vlan_id_mask;
+			enum rocker_of_dpa_table_id goto_tbl;
+			bool untagged;
+			__be16 new_vlan_id;
+		} vlan;
+		struct {
+			u32 in_lport;
+			u32 in_lport_mask;
+			__be16 eth_type;
+			u8 eth_dst[ETH_ALEN];
+			u8 eth_dst_mask[ETH_ALEN];
+			__be16 vlan_id;
+			__be16 vlan_id_mask;
+			enum rocker_of_dpa_table_id goto_tbl;
+			bool copy_to_cpu;
+		} term_mac;
+		struct {
+			__be16 eth_type;
+			__be32 dst4;
+			__be32 dst4_mask;
+			enum rocker_of_dpa_table_id goto_tbl;
+			u32 group_id;
+		} ucast_routing;
+		struct {
+			u8 eth_dst[ETH_ALEN];
+			u8 eth_dst_mask[ETH_ALEN];
+			int has_eth_dst;
+			int has_eth_dst_mask;
+			__be16 vlan_id;
+			u32 tunnel_id;
+			enum rocker_of_dpa_table_id goto_tbl;
+			u32 group_id;
+			bool copy_to_cpu;
+		} bridge;
+		struct {
+			u32 in_lport;
+			u32 in_lport_mask;
+			u8 eth_src[ETH_ALEN];
+			u8 eth_src_mask[ETH_ALEN];
+			u8 eth_dst[ETH_ALEN];
+			u8 eth_dst_mask[ETH_ALEN];
+			__be16 eth_type;
+			__be16 vlan_id;
+			__be16 vlan_id_mask;
+			u8 ip_proto;
+			u8 ip_proto_mask;
+			u8 ip_tos;
+			u8 ip_tos_mask;
+			u32 group_id;
+		} acl;
+	};
+};
+
+struct rocker_flow_tbl_entry {
+	struct hlist_node entry;
+	u32 ref_count;
+	u64 cookie;
+	struct rocker_flow_tbl_key key;
+	u32 key_crc32; /* key */
+};
+
+struct rocker_group_tbl_entry {
+	struct hlist_node entry;
+	u32 cmd;
+	u32 group_id; /* key */
+	u16 group_count;
+	u32 *group_ids;
+	union {
+		struct {
+			u8 pop_vlan;
+		} l2_interface;
+		struct {
+			u8 eth_src[ETH_ALEN];
+			u8 eth_dst[ETH_ALEN];
+			__be16 vlan_id;
+			u32 group_id;
+		} l2_rewrite;
+		struct {
+			u8 eth_src[ETH_ALEN];
+			u8 eth_dst[ETH_ALEN];
+			__be16 vlan_id;
+			bool ttl_check;
+			u32 group_id;
+		} l3_unicast;
+	};
+};
+
+struct rocker_fdb_tbl_entry {
+	struct hlist_node entry;
+	u32 key_crc32; /* key */
+	bool learned;
+	struct rocker_fdb_tbl_key {
+		u32 lport;
+		u8 addr[ETH_ALEN];
+		__be16 vlan_id;
+	} key;
+};
+
+struct rocker_internal_vlan_tbl_entry {
+	struct hlist_node entry;
+	int ifindex; /* key */
+	u32 ref_count;
+	__be16 vlan_id;
+};
+
 struct rocker_desc_info {
 	char *data; /* mapped */
 	size_t data_size;
@@ -61,11 +180,28 @@ struct rocker_dma_ring_info {
 
 struct rocker;
 
+enum {
+	ROCKER_CTRL_LINK_LOCAL_MCAST,
+	ROCKER_CTRL_LOCAL_ARP,
+	ROCKER_CTRL_IPV4_MCAST,
+	ROCKER_CTRL_IPV6_MCAST,
+	ROCKER_CTRL_DFLT_BRIDGING,
+	ROCKER_CTRL_MAX,
+};
+
+#define ROCKER_INTERNAL_VLAN_ID_BASE	0x0f00
+#define ROCKER_N_INTERNAL_VLANS		255
+#define ROCKER_VLAN_BITMAP_LEN		BITS_TO_LONGS(VLAN_N_VID)
+#define ROCKER_INTERNAL_VLAN_BITMAP_LEN	BITS_TO_LONGS(ROCKER_N_INTERNAL_VLANS)
+
 struct rocker_port {
 	struct net_device *dev;
 	struct rocker *rocker;
 	unsigned int port_number;
 	u32 lport;
+	__be16 internal_vlan_id;
+	bool ctrls[ROCKER_CTRL_MAX];
+	unsigned long vlan_bitmap[ROCKER_VLAN_BITMAP_LEN];
 	struct napi_struct napi_tx;
 	struct napi_struct napi_rx;
 	struct rocker_dma_ring_info tx_ring;
@@ -84,8 +220,76 @@ struct rocker {
 	spinlock_t cmd_ring_lock;
 	struct rocker_dma_ring_info cmd_ring;
 	struct rocker_dma_ring_info event_ring;
+	DECLARE_HASHTABLE(flow_tbl, 16);
+	spinlock_t flow_tbl_lock;
+	u64 flow_tbl_next_cookie;
+	DECLARE_HASHTABLE(group_tbl, 16);
+	spinlock_t group_tbl_lock;
+	DECLARE_HASHTABLE(fdb_tbl, 16);
+	spinlock_t fdb_tbl_lock;
+	unsigned long internal_vlan_bitmap[ROCKER_INTERNAL_VLAN_BITMAP_LEN];
+	DECLARE_HASHTABLE(internal_vlan_tbl, 8);
+	spinlock_t internal_vlan_tbl_lock;
+};
+
+static const u8 zero_mac[ETH_ALEN]   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ff_mac[ETH_ALEN]     = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static const u8 ll_mac[ETH_ALEN]     = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+static const u8 ll_mask[ETH_ALEN]    = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
+static const u8 mcast_mac[ETH_ALEN]  = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ipv4_mcast[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
+static const u8 ipv4_mask[ETH_ALEN]  = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 };
+static const u8 ipv6_mcast[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ipv6_mask[ETH_ALEN]  = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+/* Rocker priority levels for flow table entries.  Higher
+ * priority match takes precedence over lower priority match.
+ */
+
+enum {
+	ROCKER_PRIORITY_UNKNOWN = 0,
+	ROCKER_PRIORITY_IG_PORT = 1,
+	ROCKER_PRIORITY_VLAN = 1,
+	ROCKER_PRIORITY_TERM_MAC_UCAST = 0,
+	ROCKER_PRIORITY_TERM_MAC_MCAST = 1,
+	ROCKER_PRIORITY_UNICAST_ROUTING = 1,
+	ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_EXACT = 1,
+	ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_WILD = 2,
+	ROCKER_PRIORITY_BRIDGING_VLAN = 3,
+	ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_EXACT = 1,
+	ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_WILD = 2,
+	ROCKER_PRIORITY_BRIDGING_TENANT = 3,
+	ROCKER_PRIORITY_ACL_CTRL = 3,
+	ROCKER_PRIORITY_ACL_NORMAL = 2,
+	ROCKER_PRIORITY_ACL_DFLT = 1,
 };
 
+static bool rocker_vlan_id_is_internal(__be16 vlan_id)
+{
+	u16 start = ROCKER_INTERNAL_VLAN_ID_BASE;
+	u16 end = 0xffe;
+	u16 _vlan_id = ntohs(vlan_id);
+
+	return (_vlan_id >= start && _vlan_id <= end);
+}
+
+static __be16 rocker_port_vid_to_vlan(struct rocker_port *rocker_port,
+				      u16 vid, bool *pop_vlan)
+{
+	__be16 vlan_id;
+
+	if (pop_vlan)
+		*pop_vlan = false;
+	vlan_id = htons(vid);
+	if (!vlan_id) {
+		vlan_id = rocker_port->internal_vlan_id;
+		if (pop_vlan)
+			*pop_vlan = true;
+	}
+
+	return vlan_id;
+}
+
 struct rocker_wait {
 	wait_queue_head_t wait;
 	bool done;
@@ -1094,6 +1298,10 @@ static int rocker_event_link_change(struct rocker *rocker,
 	return 0;
 }
 
+#define ROCKER_OP_FLAG_REMOVE		BIT(0)
+#define ROCKER_OP_FLAG_NOWAIT		BIT(1)
+#define ROCKER_OP_FLAG_LEARNED		BIT(2)
+
 static int rocker_event_process(struct rocker *rocker,
 				struct rocker_desc_info *desc_info)
 {
@@ -1399,6 +1607,1239 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
 			       macaddr, NULL, NULL, false);
 }
 
+static int rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
+					   struct rocker_flow_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT,
+			       entry->key.ig_port.in_lport))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT_MASK,
+			       entry->key.ig_port.in_lport_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+			       entry->key.ig_port.goto_tbl))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
+					struct rocker_flow_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT,
+			       entry->key.vlan.in_lport))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->key.vlan.vlan_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+			       entry->key.vlan.vlan_id_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+			       entry->key.vlan.goto_tbl))
+		return -EMSGSIZE;
+	if (entry->key.vlan.untagged &&
+	    rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_NEW_VLAN_ID,
+			       entry->key.vlan.new_vlan_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
+					    struct rocker_flow_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT,
+			       entry->key.term_mac.in_lport))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT_MASK,
+			       entry->key.term_mac.in_lport_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+			       entry->key.term_mac.eth_type))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+			   ETH_ALEN, entry->key.term_mac.eth_dst))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+			   ETH_ALEN, entry->key.term_mac.eth_dst_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->key.term_mac.vlan_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+			       entry->key.term_mac.vlan_id_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+			       entry->key.term_mac.goto_tbl))
+		return -EMSGSIZE;
+	if (entry->key.term_mac.copy_to_cpu &&
+	    rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
+			      entry->key.term_mac.copy_to_cpu))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int
+rocker_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
+				      struct rocker_flow_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+			       entry->key.ucast_routing.eth_type))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_DST_IP,
+			       entry->key.ucast_routing.dst4))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_DST_IP_MASK,
+			       entry->key.ucast_routing.dst4_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+			       entry->key.ucast_routing.goto_tbl))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+			       entry->key.ucast_routing.group_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
+					  struct rocker_flow_tbl_entry *entry)
+{
+	if (entry->key.bridge.has_eth_dst &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+			   ETH_ALEN, entry->key.bridge.eth_dst))
+		return -EMSGSIZE;
+	if (entry->key.bridge.has_eth_dst_mask &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+			   ETH_ALEN, entry->key.bridge.eth_dst_mask))
+		return -EMSGSIZE;
+	if (entry->key.bridge.vlan_id &&
+	    rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->key.bridge.vlan_id))
+		return -EMSGSIZE;
+	if (entry->key.bridge.tunnel_id &&
+	    rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_TUNNEL_ID,
+			       entry->key.bridge.tunnel_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+			       entry->key.bridge.goto_tbl))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+			       entry->key.bridge.group_id))
+		return -EMSGSIZE;
+	if (entry->key.bridge.copy_to_cpu &&
+	    rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
+			      entry->key.bridge.copy_to_cpu))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
+				       struct rocker_flow_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT,
+			       entry->key.acl.in_lport))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_LPORT_MASK,
+			       entry->key.acl.in_lport_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+			   ETH_ALEN, entry->key.acl.eth_src))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC_MASK,
+			   ETH_ALEN, entry->key.acl.eth_src_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+			   ETH_ALEN, entry->key.acl.eth_dst))
+		return -EMSGSIZE;
+	if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+			   ETH_ALEN, entry->key.acl.eth_dst_mask))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+			       entry->key.acl.eth_type))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->key.acl.vlan_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+			       entry->key.acl.vlan_id_mask))
+		return -EMSGSIZE;
+
+	switch (ntohs(entry->key.acl.eth_type)) {
+	case ETH_P_IP:
+	case ETH_P_IPV6:
+		if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_PROTO,
+				      entry->key.acl.ip_proto))
+			return -EMSGSIZE;
+		if (rocker_tlv_put_u8(desc_info,
+				      ROCKER_TLV_OF_DPA_IP_PROTO_MASK,
+				      entry->key.acl.ip_proto_mask))
+			return -EMSGSIZE;
+		if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_DSCP,
+				      entry->key.acl.ip_tos & 0x3f))
+			return -EMSGSIZE;
+		if (rocker_tlv_put_u8(desc_info,
+				      ROCKER_TLV_OF_DPA_IP_DSCP_MASK,
+				      entry->key.acl.ip_tos_mask & 0x3f))
+			return -EMSGSIZE;
+		if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_ECN,
+				      (entry->key.acl.ip_tos & 0xc0) >> 6))
+			return -EMSGSIZE;
+		if (rocker_tlv_put_u8(desc_info,
+				      ROCKER_TLV_OF_DPA_IP_ECN_MASK,
+				      (entry->key.acl.ip_tos_mask & 0xc0) >> 6))
+			return -EMSGSIZE;
+		break;
+	}
+
+	if (entry->key.acl.group_id != ROCKER_GROUP_NONE &&
+	    rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+			       entry->key.acl.group_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_add(struct rocker *rocker,
+				   struct rocker_port *rocker_port,
+				   struct rocker_desc_info *desc_info,
+				   void *priv)
+{
+	struct rocker_flow_tbl_entry *entry = priv;
+	struct rocker_tlv *cmd_info;
+	int err = 0;
+
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+			       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD))
+		return -EMSGSIZE;
+	cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+	if (!cmd_info)
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_TABLE_ID,
+			       entry->key.tbl_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_PRIORITY,
+			       entry->key.priority))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_HARDTIME, 0))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
+			       entry->cookie))
+		return -EMSGSIZE;
+
+	switch (entry->key.tbl_id) {
+	case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
+		err = rocker_cmd_flow_tbl_add_ig_port(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_TABLE_ID_VLAN:
+		err = rocker_cmd_flow_tbl_add_vlan(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
+		err = rocker_cmd_flow_tbl_add_term_mac(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
+		err = rocker_cmd_flow_tbl_add_ucast_routing(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
+		err = rocker_cmd_flow_tbl_add_bridge(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
+		err = rocker_cmd_flow_tbl_add_acl(desc_info, entry);
+		break;
+	default:
+		err = -ENOTSUPP;
+		break;
+	}
+
+	if (err)
+		return err;
+
+	rocker_tlv_nest_end(desc_info, cmd_info);
+
+	return 0;
+}
+
+static int rocker_cmd_flow_tbl_del(struct rocker *rocker,
+				   struct rocker_port *rocker_port,
+				   struct rocker_desc_info *desc_info,
+				   void *priv)
+{
+	const struct rocker_flow_tbl_entry *entry = priv;
+	struct rocker_tlv *cmd_info;
+
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+			       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL))
+		return -EMSGSIZE;
+	cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+	if (!cmd_info)
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
+			       entry->cookie))
+		return -EMSGSIZE;
+	rocker_tlv_nest_end(desc_info, cmd_info);
+
+	return 0;
+}
+
+static int
+rocker_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
+				      struct rocker_group_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_OUT_LPORT,
+			       ROCKER_GROUP_PORT_GET(entry->group_id)))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_POP_VLAN,
+			      entry->l2_interface.pop_vlan))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int
+rocker_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
+				    struct rocker_group_tbl_entry *entry)
+{
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
+			       entry->l2_rewrite.group_id))
+		return -EMSGSIZE;
+	if (!is_zero_ether_addr(entry->l2_rewrite.eth_src) &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+			   ETH_ALEN, entry->l2_rewrite.eth_src))
+		return -EMSGSIZE;
+	if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst) &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+			   ETH_ALEN, entry->l2_rewrite.eth_dst))
+		return -EMSGSIZE;
+	if (entry->l2_rewrite.vlan_id &&
+	    rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->l2_rewrite.vlan_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int
+rocker_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
+				   struct rocker_group_tbl_entry *entry)
+{
+	int i;
+	struct rocker_tlv *group_ids;
+
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GROUP_COUNT,
+			       entry->group_count))
+		return -EMSGSIZE;
+
+	group_ids = rocker_tlv_nest_start(desc_info,
+					  ROCKER_TLV_OF_DPA_GROUP_IDS);
+	if (!group_ids)
+		return -EMSGSIZE;
+
+	for (i = 0; i < entry->group_count; i++)
+		/* Note TLV array is 1-based */
+		if (rocker_tlv_put_u32(desc_info, i + 1, entry->group_ids[i]))
+			return -EMSGSIZE;
+
+	rocker_tlv_nest_end(desc_info, group_ids);
+
+	return 0;
+}
+
+static int
+rocker_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
+				    struct rocker_group_tbl_entry *entry)
+{
+	if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+			   ETH_ALEN, entry->l3_unicast.eth_src))
+		return -EMSGSIZE;
+	if (!is_zero_ether_addr(entry->l3_unicast.eth_dst) &&
+	    rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+			   ETH_ALEN, entry->l3_unicast.eth_dst))
+		return -EMSGSIZE;
+	if (entry->l3_unicast.vlan_id &&
+	    rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+			       entry->l3_unicast.vlan_id))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_TTL_CHECK,
+			      entry->l3_unicast.ttl_check))
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
+			       entry->l3_unicast.group_id))
+		return -EMSGSIZE;
+
+	return 0;
+}
+
+static int rocker_cmd_group_tbl_add(struct rocker *rocker,
+				    struct rocker_port *rocker_port,
+				    struct rocker_desc_info *desc_info,
+				    void *priv)
+{
+	struct rocker_group_tbl_entry *entry = priv;
+	struct rocker_tlv *cmd_info;
+	int err = 0;
+
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+		return -EMSGSIZE;
+	cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+	if (!cmd_info)
+		return -EMSGSIZE;
+
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+			       entry->group_id))
+		return -EMSGSIZE;
+
+	switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
+		err = rocker_cmd_group_tbl_add_l2_interface(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
+		err = rocker_cmd_group_tbl_add_l2_rewrite(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
+		err = rocker_cmd_group_tbl_add_group_ids(desc_info, entry);
+		break;
+	case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
+		err = rocker_cmd_group_tbl_add_l3_unicast(desc_info, entry);
+		break;
+	default:
+		err = -ENOTSUPP;
+		break;
+	}
+
+	if (err)
+		return err;
+
+	rocker_tlv_nest_end(desc_info, cmd_info);
+
+	return 0;
+}
+
+static int rocker_cmd_group_tbl_del(struct rocker *rocker,
+				    struct rocker_port *rocker_port,
+				    struct rocker_desc_info *desc_info,
+				    void *priv)
+{
+	const struct rocker_group_tbl_entry *entry = priv;
+	struct rocker_tlv *cmd_info;
+
+	if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+		return -EMSGSIZE;
+	cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+	if (!cmd_info)
+		return -EMSGSIZE;
+	if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+			       entry->group_id))
+		return -EMSGSIZE;
+	rocker_tlv_nest_end(desc_info, cmd_info);
+
+	return 0;
+}
+
+/*****************************************
+ * Flow, group, FDB, internal VLAN tables
+ *****************************************/
+
+static int rocker_init_tbls(struct rocker *rocker)
+{
+	hash_init(rocker->flow_tbl);
+	spin_lock_init(&rocker->flow_tbl_lock);
+
+	hash_init(rocker->group_tbl);
+	spin_lock_init(&rocker->group_tbl_lock);
+
+	hash_init(rocker->fdb_tbl);
+	spin_lock_init(&rocker->fdb_tbl_lock);
+
+	hash_init(rocker->internal_vlan_tbl);
+	spin_lock_init(&rocker->internal_vlan_tbl_lock);
+
+	return 0;
+}
+
+static void rocker_free_tbls(struct rocker *rocker)
+{
+	unsigned long flags;
+	struct rocker_flow_tbl_entry *flow_entry;
+	struct rocker_group_tbl_entry *group_entry;
+	struct rocker_fdb_tbl_entry *fdb_entry;
+	struct rocker_internal_vlan_tbl_entry *internal_vlan_entry;
+	struct hlist_node *tmp;
+	int bkt;
+
+	spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+	hash_for_each_safe(rocker->flow_tbl, bkt, tmp, flow_entry, entry)
+		hash_del(&flow_entry->entry);
+	spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+
+	spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+	hash_for_each_safe(rocker->group_tbl, bkt, tmp, group_entry, entry)
+		hash_del(&group_entry->entry);
+	spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+
+	spin_lock_irqsave(&rocker->fdb_tbl_lock, flags);
+	hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, fdb_entry, entry)
+		hash_del(&fdb_entry->entry);
+	spin_unlock_irqrestore(&rocker->fdb_tbl_lock, flags);
+
+	spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, flags);
+	hash_for_each_safe(rocker->internal_vlan_tbl, bkt,
+			   tmp, internal_vlan_entry, entry)
+		hash_del(&internal_vlan_entry->entry);
+	spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, flags);
+}
+
+static struct rocker_flow_tbl_entry *
+rocker_flow_tbl_find(struct rocker *rocker, struct rocker_flow_tbl_entry *match)
+{
+	struct rocker_flow_tbl_entry *found;
+
+	hash_for_each_possible(rocker->flow_tbl, found, entry, match->key_crc32) {
+		if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
+			return found;
+	}
+
+	return NULL;
+}
+
+static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
+			       struct rocker_flow_tbl_entry *match,
+			       bool nowait)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_flow_tbl_entry *found;
+	unsigned long flags;
+	bool add_to_hw = false;
+	int err = 0;
+
+	match->key_crc32 = crc32(~0, &match->key, sizeof(match->key));
+
+	spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+
+	found = rocker_flow_tbl_find(rocker, match);
+
+	if (found) {
+		kfree(match);
+	} else {
+		found = match;
+		found->cookie = rocker->flow_tbl_next_cookie++;
+		hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
+		add_to_hw = true;
+	}
+
+	found->ref_count++;
+
+	spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+
+	if (add_to_hw) {
+		err = rocker_cmd_exec(rocker, rocker_port,
+				      rocker_cmd_flow_tbl_add,
+				      found, NULL, NULL, nowait);
+		if (err) {
+			spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+			hash_del(&found->entry);
+			spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+			kfree(found);
+		}
+	}
+
+	return err;
+}
+
+static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
+			       struct rocker_flow_tbl_entry *match,
+			       bool nowait)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_flow_tbl_entry *found;
+	unsigned long flags;
+	bool del_from_hw = false;
+	int err = 0;
+
+	match->key_crc32 = crc32(~0, &match->key, sizeof(match->key));
+
+	spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
+
+	found = rocker_flow_tbl_find(rocker, match);
+
+	if (found) {
+		found->ref_count--;
+		if (found->ref_count == 0) {
+			hash_del(&found->entry);
+			del_from_hw = true;
+		}
+	}
+
+	spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
+
+	kfree(match);
+
+	if (del_from_hw) {
+		err = rocker_cmd_exec(rocker, rocker_port,
+				      rocker_cmd_flow_tbl_del,
+				      found, NULL, NULL, nowait);
+		kfree(found);
+	}
+
+	return err;
+}
+
+static gfp_t rocker_op_flags_gfp(int flags)
+{
+	return flags & ROCKER_OP_FLAG_NOWAIT ? GFP_ATOMIC : GFP_KERNEL;
+}
+
+static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
+			      int flags, struct rocker_flow_tbl_entry *entry)
+{
+	bool nowait = flags & ROCKER_OP_FLAG_NOWAIT;
+
+	if (flags & ROCKER_OP_FLAG_REMOVE)
+		return rocker_flow_tbl_del(rocker_port, entry, nowait);
+	else
+		return rocker_flow_tbl_add(rocker_port, entry, nowait);
+}
+
+static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
+				   int flags, u32 in_lport, u32 in_lport_mask,
+				   enum rocker_of_dpa_table_id goto_tbl)
+{
+	struct rocker_flow_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	entry->key.priority = ROCKER_PRIORITY_IG_PORT;
+	entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
+	entry->key.ig_port.in_lport = in_lport;
+	entry->key.ig_port.in_lport_mask = in_lport_mask;
+	entry->key.ig_port.goto_tbl = goto_tbl;
+
+	return rocker_flow_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
+				int flags, u32 in_lport,
+				__be16 vlan_id, __be16 vlan_id_mask,
+				enum rocker_of_dpa_table_id goto_tbl,
+				bool untagged, __be16 new_vlan_id)
+{
+	struct rocker_flow_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	entry->key.priority = ROCKER_PRIORITY_VLAN;
+	entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
+	entry->key.vlan.in_lport = in_lport;
+	entry->key.vlan.vlan_id = vlan_id;
+	entry->key.vlan.vlan_id_mask = vlan_id_mask;
+	entry->key.vlan.goto_tbl = goto_tbl;
+
+	entry->key.vlan.untagged = untagged;
+	entry->key.vlan.new_vlan_id = new_vlan_id;
+
+	return rocker_flow_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
+				    u32 in_lport, u32 in_lport_mask,
+				    __be16 eth_type, const u8 *eth_dst,
+				    const u8 *eth_dst_mask, __be16 vlan_id,
+				    __be16 vlan_id_mask, bool copy_to_cpu,
+				    int flags)
+{
+	struct rocker_flow_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	if (is_multicast_ether_addr(eth_dst)) {
+		entry->key.priority = ROCKER_PRIORITY_TERM_MAC_MCAST;
+		entry->key.term_mac.goto_tbl =
+			 ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
+	} else {
+		entry->key.priority = ROCKER_PRIORITY_TERM_MAC_UCAST;
+		entry->key.term_mac.goto_tbl =
+			 ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
+	}
+
+	entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+	entry->key.term_mac.in_lport = in_lport;
+	entry->key.term_mac.in_lport_mask = in_lport_mask;
+	entry->key.term_mac.eth_type = eth_type;
+	ether_addr_copy(entry->key.term_mac.eth_dst, eth_dst);
+	ether_addr_copy(entry->key.term_mac.eth_dst_mask, eth_dst_mask);
+	entry->key.term_mac.vlan_id = vlan_id;
+	entry->key.term_mac.vlan_id_mask = vlan_id_mask;
+	entry->key.term_mac.copy_to_cpu = copy_to_cpu;
+
+	return rocker_flow_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
+				  int flags,
+				  const u8 *eth_dst, const u8 *eth_dst_mask,
+				  __be16 vlan_id, u32 tunnel_id,
+				  enum rocker_of_dpa_table_id goto_tbl,
+				  u32 group_id, bool copy_to_cpu)
+{
+	struct rocker_flow_tbl_entry *entry;
+	u32 priority;
+	bool vlan_bridging = !!vlan_id;
+	bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
+	bool wild = false;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
+
+	if (eth_dst) {
+		entry->key.bridge.has_eth_dst = 1;
+		ether_addr_copy(entry->key.bridge.eth_dst, eth_dst);
+	}
+	if (eth_dst_mask) {
+		entry->key.bridge.has_eth_dst_mask = 1;
+		ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
+		if (memcmp(eth_dst_mask, ff_mac, ETH_ALEN))
+			wild = true;
+	}
+
+	priority = ROCKER_PRIORITY_UNKNOWN;
+	if (vlan_bridging & dflt & wild)
+		priority = ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_WILD;
+	else if (vlan_bridging & dflt & !wild)
+		priority = ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_EXACT;
+	else if (vlan_bridging & !dflt)
+		priority = ROCKER_PRIORITY_BRIDGING_VLAN;
+	else if (!vlan_bridging & dflt & wild)
+		priority = ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_WILD;
+	else if (!vlan_bridging & dflt & !wild)
+		priority = ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_EXACT;
+	else if (!vlan_bridging & !dflt)
+		priority = ROCKER_PRIORITY_BRIDGING_TENANT;
+
+	entry->key.priority = priority;
+	entry->key.bridge.vlan_id = vlan_id;
+	entry->key.bridge.tunnel_id = tunnel_id;
+	entry->key.bridge.goto_tbl = goto_tbl;
+	entry->key.bridge.group_id = group_id;
+	entry->key.bridge.copy_to_cpu = copy_to_cpu;
+
+	return rocker_flow_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
+			       int flags, u32 in_lport,
+			       u32 in_lport_mask,
+			       const u8 *eth_src, const u8 *eth_src_mask,
+			       const u8 *eth_dst, const u8 *eth_dst_mask,
+			       __be16 eth_type,
+			       __be16 vlan_id, __be16 vlan_id_mask,
+			       u8 ip_proto, u8 ip_proto_mask,
+			       u8 ip_tos, u8 ip_tos_mask,
+			       u32 group_id)
+{
+	u32 priority;
+	struct rocker_flow_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	priority = ROCKER_PRIORITY_ACL_NORMAL;
+	if (eth_dst && eth_dst_mask) {
+		if (memcmp(eth_dst_mask, mcast_mac, ETH_ALEN) == 0)
+			priority = ROCKER_PRIORITY_ACL_DFLT;
+		else if (is_link_local_ether_addr(eth_dst))
+			priority = ROCKER_PRIORITY_ACL_CTRL;
+	}
+
+	entry->key.priority = priority;
+	entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+	entry->key.acl.in_lport = in_lport;
+	entry->key.acl.in_lport_mask = in_lport_mask;
+
+	if (eth_src)
+		ether_addr_copy(entry->key.acl.eth_src, eth_src);
+	if (eth_src_mask)
+		ether_addr_copy(entry->key.acl.eth_src_mask, eth_src_mask);
+	if (eth_dst)
+		ether_addr_copy(entry->key.acl.eth_dst, eth_dst);
+	if (eth_dst_mask)
+		ether_addr_copy(entry->key.acl.eth_dst_mask, eth_dst_mask);
+
+	entry->key.acl.eth_type = eth_type;
+	entry->key.acl.vlan_id = vlan_id;
+	entry->key.acl.vlan_id_mask = vlan_id_mask;
+	entry->key.acl.ip_proto = ip_proto;
+	entry->key.acl.ip_proto_mask = ip_proto_mask;
+	entry->key.acl.ip_tos = ip_tos;
+	entry->key.acl.ip_tos_mask = ip_tos_mask;
+	entry->key.acl.group_id = group_id;
+
+	return rocker_flow_tbl_do(rocker_port, flags, entry);
+}
+
+static struct rocker_group_tbl_entry *
+rocker_group_tbl_find(struct rocker *rocker,
+		      struct rocker_group_tbl_entry *match)
+{
+	struct rocker_group_tbl_entry *found;
+
+	hash_for_each_possible(rocker->group_tbl, found,
+			       entry, match->group_id) {
+		if (found->group_id == match->group_id)
+			return found;
+	}
+
+	return NULL;
+}
+
+static void rocker_group_tbl_entry_free(struct rocker_group_tbl_entry *entry)
+{
+	switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
+	case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
+		kfree(entry->group_ids);
+		break;
+	default:
+		break;
+	}
+	kfree(entry);
+}
+
+static int rocker_group_tbl_add(struct rocker_port *rocker_port,
+				struct rocker_group_tbl_entry *match,
+				bool nowait)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_group_tbl_entry *found;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+
+	found = rocker_group_tbl_find(rocker, match);
+
+	if (found) {
+		hash_del(&found->entry);
+		rocker_group_tbl_entry_free(found);
+		found = match;
+		found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
+	} else {
+		found = match;
+		found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
+	}
+
+	hash_add(rocker->group_tbl, &found->entry, found->group_id);
+
+	spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+
+	if (found->cmd)
+		err = rocker_cmd_exec(rocker, rocker_port,
+				      rocker_cmd_group_tbl_add,
+				      found, NULL, NULL, nowait);
+
+	return err;
+}
+
+static int rocker_group_tbl_del(struct rocker_port *rocker_port,
+				struct rocker_group_tbl_entry *match,
+				bool nowait)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_group_tbl_entry *found;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&rocker->group_tbl_lock, flags);
+
+	found = rocker_group_tbl_find(rocker, match);
+
+	if (found) {
+		hash_del(&found->entry);
+		found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
+	}
+
+	spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
+
+	rocker_group_tbl_entry_free(match);
+
+	if (found) {
+		err = rocker_cmd_exec(rocker, rocker_port,
+				      rocker_cmd_group_tbl_del,
+				      found, NULL, NULL, nowait);
+		rocker_group_tbl_entry_free(found);
+	}
+
+	return err;
+}
+
+static int rocker_group_tbl_do(struct rocker_port *rocker_port,
+			       int flags, struct rocker_group_tbl_entry *entry)
+{
+	bool nowait = flags & ROCKER_OP_FLAG_NOWAIT;
+
+	if (flags & ROCKER_OP_FLAG_REMOVE)
+		return rocker_group_tbl_del(rocker_port, entry, nowait);
+	else
+		return rocker_group_tbl_add(rocker_port, entry, nowait);
+}
+
+static int rocker_group_l2_interface(struct rocker_port *rocker_port,
+				     int flags, __be16 vlan_id,
+				     u32 out_lport, int pop_vlan)
+{
+	struct rocker_group_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
+	entry->l2_interface.pop_vlan = pop_vlan;
+
+	return rocker_group_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
+				   int flags, u8 group_count,
+				   u32 *group_ids, u32 group_id)
+{
+	struct rocker_group_tbl_entry *entry;
+
+	entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+	if (!entry)
+		return -ENOMEM;
+
+	entry->group_id = group_id;
+	entry->group_count = group_count;
+
+	entry->group_ids = kcalloc(group_count, sizeof(u32),
+				   rocker_op_flags_gfp(flags));
+	if (!entry->group_ids) {
+		kfree(entry);
+		return -ENOMEM;
+	}
+	memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
+
+	return rocker_group_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_group_l2_flood(struct rocker_port *rocker_port,
+				 int flags, __be16 vlan_id,
+				 u8 group_count, u32 *group_ids,
+				 u32 group_id)
+{
+	return rocker_group_l2_fan_out(rocker_port, flags,
+				       group_count, group_ids,
+				       group_id);
+}
+
+static struct rocker_ctrl {
+	const u8 *eth_dst;
+	const u8 *eth_dst_mask;
+	u16 eth_type;
+	bool acl;
+	bool bridge;
+	bool term;
+	bool copy_to_cpu;
+} rocker_ctrls[] = {
+	[ROCKER_CTRL_LINK_LOCAL_MCAST] = {
+		/* pass link local multicast pkts up to CPU for filtering */
+		.eth_dst = ll_mac,
+		.eth_dst_mask = ll_mask,
+		.acl = true,
+	},
+	[ROCKER_CTRL_LOCAL_ARP] = {
+		/* pass local ARP pkts up to CPU */
+		.eth_dst = zero_mac,
+		.eth_dst_mask = zero_mac,
+		.eth_type = htons(ETH_P_ARP),
+		.acl = true,
+	},
+	[ROCKER_CTRL_IPV4_MCAST] = {
+		/* pass IPv4 mcast pkts up to CPU, RFC 1112 */
+		.eth_dst = ipv4_mcast,
+		.eth_dst_mask = ipv4_mask,
+		.eth_type = htons(ETH_P_IP),
+		.term  = true,
+		.copy_to_cpu = true,
+	},
+	[ROCKER_CTRL_IPV6_MCAST] = {
+		/* pass IPv6 mcast pkts up to CPU, RFC 2464 */
+		.eth_dst = ipv6_mcast,
+		.eth_dst_mask = ipv6_mask,
+		.eth_type = htons(ETH_P_IPV6),
+		.term  = true,
+		.copy_to_cpu = true,
+	},
+	[ROCKER_CTRL_DFLT_BRIDGING] = {
+		/* flood any pkts on vlan */
+		.bridge = true,
+		.copy_to_cpu = true,
+	},
+};
+
+static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
+				     int flags, struct rocker_ctrl *ctrl,
+				     __be16 vlan_id)
+{
+	u32 in_lport = rocker_port->lport;
+	u32 in_lport_mask = 0xffffffff;
+	u32 out_lport = 0;
+	u8 *eth_src = NULL;
+	u8 *eth_src_mask = NULL;
+	__be16 vlan_id_mask = htons(0xffff);
+	u8 ip_proto = 0;
+	u8 ip_proto_mask = 0;
+	u8 ip_tos = 0;
+	u8 ip_tos_mask = 0;
+	u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
+	int err;
+
+	err = rocker_flow_tbl_acl(rocker_port, flags,
+				  in_lport, in_lport_mask,
+				  eth_src, eth_src_mask,
+				  ctrl->eth_dst, ctrl->eth_dst_mask,
+				  ctrl->eth_type,
+				  vlan_id, vlan_id_mask,
+				  ip_proto, ip_proto_mask,
+				  ip_tos, ip_tos_mask,
+				  group_id);
+
+	if (err)
+		netdev_err(rocker_port->dev, "Error (%d) ctrl ACL\n", err);
+
+	return err;
+}
+
+static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
+				      int flags, struct rocker_ctrl *ctrl,
+				      __be16 vlan_id)
+{
+	u32 in_lport_mask = 0xffffffff;
+	__be16 vlan_id_mask = htons(0xffff);
+	int err;
+
+	if (ntohs(vlan_id) == 0)
+		vlan_id = rocker_port->internal_vlan_id;
+
+	err = rocker_flow_tbl_term_mac(rocker_port,
+				       rocker_port->lport, in_lport_mask,
+				       ctrl->eth_type, ctrl->eth_dst,
+				       ctrl->eth_dst_mask, vlan_id,
+				       vlan_id_mask, ctrl->copy_to_cpu,
+				       flags);
+
+	if (err)
+		netdev_err(rocker_port->dev, "Error (%d) ctrl term\n", err);
+
+	return err;
+}
+
+static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port, int flags,
+				 struct rocker_ctrl *ctrl, __be16 vlan_id)
+{
+	if (ctrl->acl)
+		return rocker_port_ctrl_vlan_acl(rocker_port, flags,
+						 ctrl, vlan_id);
+
+	if (ctrl->term)
+		return rocker_port_ctrl_vlan_term(rocker_port, flags,
+						  ctrl, vlan_id);
+
+	return -EOPNOTSUPP;
+}
+
+static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
+				     int flags, __be16 vlan_id)
+{
+	int err = 0;
+	int i;
+
+	for (i = 0; i < ROCKER_CTRL_MAX; i++) {
+		if (rocker_port->ctrls[i]) {
+			err = rocker_port_ctrl_vlan(rocker_port, flags,
+						    &rocker_ctrls[i], vlan_id);
+			if (err)
+				return err;
+		}
+	}
+
+	return err;
+}
+
+static int rocker_port_ctrl(struct rocker_port *rocker_port, int flags,
+			    struct rocker_ctrl *ctrl)
+{
+	u16 vid;
+	int err = 0;
+
+	for (vid = 1; vid < VLAN_N_VID; vid++) {
+		if (!test_bit(vid, rocker_port->vlan_bitmap))
+			continue;
+		err = rocker_port_ctrl_vlan(rocker_port, flags,
+					    ctrl, htons(vid));
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
+{
+	enum rocker_of_dpa_table_id goto_tbl;
+	u32 in_lport;
+	u32 in_lport_mask;
+	int err;
+
+	/* Normal Ethernet Frames.  Matches pkts from any local physical
+	 * ports.  Goto VLAN tbl.
+	 */
+
+	in_lport = 0;
+	in_lport_mask = 0xffff0000;
+	goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
+
+	err = rocker_flow_tbl_ig_port(rocker_port, flags,
+				      in_lport, in_lport_mask,
+				      goto_tbl);
+	if (err)
+		netdev_err(rocker_port->dev,
+			   "Error (%d) ingress port table entry\n", err);
+
+	return err;
+}
+
+static int rocker_port_router_mac(struct rocker_port *rocker_port,
+				  int flags, __be16 vlan_id)
+{
+	u32 in_lport_mask = 0xffffffff;
+	__be16 eth_type;
+	const u8 *dst_mac_mask = ff_mac;
+	__be16 vlan_id_mask = htons(0xffff);
+	bool copy_to_cpu = false;
+	int err;
+
+	if (ntohs(vlan_id) == 0)
+		vlan_id = rocker_port->internal_vlan_id;
+
+	eth_type = htons(ETH_P_IP);
+	err = rocker_flow_tbl_term_mac(rocker_port,
+				       rocker_port->lport, in_lport_mask,
+				       eth_type, rocker_port->dev->dev_addr,
+				       dst_mac_mask, vlan_id, vlan_id_mask,
+				       copy_to_cpu, flags);
+	if (err)
+		return err;
+
+	eth_type = htons(ETH_P_IPV6);
+	err = rocker_flow_tbl_term_mac(rocker_port,
+				       rocker_port->lport, in_lport_mask,
+				       eth_type, rocker_port->dev->dev_addr,
+				       dst_mac_mask, vlan_id, vlan_id_mask,
+				       copy_to_cpu, flags);
+
+	return err;
+}
+
+static struct rocker_internal_vlan_tbl_entry *
+rocker_internal_vlan_tbl_find(struct rocker *rocker, int ifindex)
+{
+	struct rocker_internal_vlan_tbl_entry *found;
+
+	hash_for_each_possible(rocker->internal_vlan_tbl,
+			       found, entry, ifindex) {
+		if (found->ifindex == ifindex)
+			return found;
+	}
+
+	return NULL;
+}
+
+static __be16 rocker_port_internal_vlan_id_get(struct rocker_port *rocker_port,
+					       int ifindex)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_internal_vlan_tbl_entry *entry;
+	struct rocker_internal_vlan_tbl_entry *found;
+	unsigned long lock_flags;
+	int i;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return 0;
+
+	entry->ifindex = ifindex;
+
+	spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, lock_flags);
+
+	found = rocker_internal_vlan_tbl_find(rocker, ifindex);
+	if (found) {
+		kfree(entry);
+		goto found;
+	}
+
+	found = entry;
+	hash_add(rocker->internal_vlan_tbl, &found->entry, found->ifindex);
+
+	for (i = 0; i < ROCKER_N_INTERNAL_VLANS; i++) {
+		if (test_and_set_bit(i, rocker->internal_vlan_bitmap))
+			continue;
+		found->vlan_id = htons(ROCKER_INTERNAL_VLAN_ID_BASE + i);
+		goto found;
+	}
+
+	netdev_err(rocker_port->dev, "Out of internal VLAN IDs\n");
+
+found:
+	found->ref_count++;
+	spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, lock_flags);
+
+	return found->vlan_id;
+}
+
+static void rocker_port_internal_vlan_id_put(struct rocker_port *rocker_port,
+					     int ifindex)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_internal_vlan_tbl_entry *found;
+	unsigned long lock_flags;
+	unsigned long bit;
+
+	spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, lock_flags);
+
+	found = rocker_internal_vlan_tbl_find(rocker, ifindex);
+	if (!found) {
+		netdev_err(rocker_port->dev,
+			   "ifindex (%d) not found in internal VLAN tbl\n",
+			   ifindex);
+		goto not_found;
+	}
+
+	if (--found->ref_count <= 0) {
+		bit = ntohs(found->vlan_id) - ROCKER_INTERNAL_VLAN_ID_BASE;
+		clear_bit(bit, rocker->internal_vlan_bitmap);
+		hash_del(&found->entry);
+		kfree(found);
+	}
+
+not_found:
+	spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, lock_flags);
+}
+
 /*****************
  * Net device ops
  *****************/
@@ -1768,10 +3209,14 @@ static void rocker_carrier_init(struct rocker_port *rocker_port)
 
 static void rocker_remove_ports(struct rocker *rocker)
 {
+	struct rocker_port *rocker_port;
 	int i;
 
-	for (i = 0; i < rocker->port_count; i++)
-		unregister_netdev(rocker->ports[i]->dev);
+	for (i = 0; i < rocker->port_count; i++) {
+		rocker_port = rocker->ports[i];
+		rocker_port_ig_tbl(rocker_port, ROCKER_OP_FLAG_REMOVE);
+		unregister_netdev(rocker_port->dev);
+	}
 	kfree(rocker->ports);
 }
 
@@ -1823,8 +3268,18 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
 	}
 	rocker->ports[port_number] = rocker_port;
 
+	rocker_port->internal_vlan_id =
+		rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
+	err = rocker_port_ig_tbl(rocker_port, 0);
+	if (err) {
+		dev_err(&pdev->dev, "install ig port table failed\n");
+		goto err_port_ig_tbl;
+	}
+
 	return 0;
 
+err_port_ig_tbl:
+	unregister_netdev(dev);
 err_register_netdev:
 	free_netdev(dev);
 	return err;
@@ -1981,6 +3436,12 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	rocker->hw.id = rocker_read64(rocker, SWITCH_ID);
 
+	err = rocker_init_tbls(rocker);
+	if (err) {
+		dev_err(&pdev->dev, "cannot init rocker tables\n");
+		goto err_init_tbls;
+	}
+
 	err = rocker_probe_ports(rocker);
 	if (err) {
 		dev_err(&pdev->dev, "failed to probe ports\n");
@@ -1992,6 +3453,8 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	return 0;
 
 err_probe_ports:
+	rocker_free_tbls(rocker);
+err_init_tbls:
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
 err_request_event_irq:
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
@@ -2017,6 +3480,7 @@ static void rocker_remove(struct pci_dev *pdev)
 {
 	struct rocker *rocker = pci_get_drvdata(pdev);
 
+	rocker_free_tbls(rocker);
 	rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
 	rocker_remove_ports(rocker);
 	free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
Signature · 1 line
1.9.3
author maintainer
#68 lore raw

PATCH v2 10/10 rocker: implement L2 bridge offloading

In reply to Jiri Pirko

From: Scott Feldman <[email protected]>

Add L2 bridge offloading support to rocker driver. Here, the Linux bridge driver is used to collect swdev ports into a tagged (or untagged) VLAN bridge. The swdev will offload from the bridge driver the following L2 bridging functions:

- Learning of neighbor MAC addresses on VLAN X Learned mac/vlan is
installed in bridge FDB. (And removed when device unlearns mac/vlan). Learning must be turned off on each bridge port to disable the feature in the bridge driver.

- Flooding of multicast/broadcast and unknown unicast pkts to (STP) active ports in bridge. The bridge driver is unaware of the flooding happening at the device level. Flooding must be turned off on each bridge port to disable the feature on the bridge driver.

- STP port state is pushed down to driver/device. The bridge still processes STP BDPUs and maintains port STP state (for all VLANs in bridge), but the driver/device must be notified of port STP state change to program the device.

Multiple (VLAN) bridges are supported. The device (implemented per the OF-DPA spec) must use a portion of the VLAN namespace for internal VLANs. Right now, the upper 255 VLANs (0xf00 to 0xffe) are used as internal VLAN IDs for untagged traffic and are not available as port VLANs.

The driver uses the following interfaces:

1. To track VLAN add/del on ports in bridge:

.ndo_vlan_rx_add_vid
.ndo_vlan_rx_kill_vid

2. To track port add/del membership in bridge:

NETDEV_CHANGEUPPER netdevice notifier

3. To catch static FDB entries installed on bridge/vlan by user using netlink:

.ndo_sw_port_fdb_add
.ndo_sw_port_fdb_del

4. To be notified on port STP state change:

.ndo_sw_port_stp_update

5. To notify bridge driver on learned/forgotten mac/vlans on bridge port:

br_fdb_learn_add
br_fdb_learn_del

---
 drivers/net/ethernet/rocker/rocker.c | 660 ++++++++++++++++++++++++++++++++++-
 1 file changed, 659 insertions(+), 1 deletion(-)
drivers/net/ethernet/rocker/rocker.c +659 -1
index ea58a4f..17ffa30 100644
@@ -28,6 +28,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
 #include <linux/bitops.h>
 #include <net/switchdev.h>
 #include <net/rtnetlink.h>
@@ -196,10 +197,12 @@ enum {
 
 struct rocker_port {
 	struct net_device *dev;
+	struct net_device *bridge_dev;
 	struct rocker *rocker;
 	unsigned int port_number;
 	u32 lport;
 	__be16 internal_vlan_id;
+	int stp_state;
 	bool ctrls[ROCKER_CTRL_MAX];
 	unsigned long vlan_bitmap[ROCKER_VLAN_BITMAP_LEN];
 	struct napi_struct napi_tx;
@@ -290,6 +293,20 @@ static __be16 rocker_port_vid_to_vlan(struct rocker_port *rocker_port,
 	return vlan_id;
 }
 
+static u16 rocker_port_vlan_to_vid(struct rocker_port *rocker_port,
+				   __be16 vlan_id)
+{
+	if (rocker_vlan_id_is_internal(vlan_id))
+		return 0;
+
+	return ntohs(vlan_id);
+}
+
+static bool rocker_port_is_bridged(struct rocker_port *rocker_port)
+{
+	return !!rocker_port->bridge_dev;
+}
+
 struct rocker_wait {
 	wait_queue_head_t wait;
 	bool done;
@@ -1302,6 +1319,42 @@ static int rocker_event_link_change(struct rocker *rocker,
 #define ROCKER_OP_FLAG_NOWAIT		BIT(1)
 #define ROCKER_OP_FLAG_LEARNED		BIT(2)
 
+static int rocker_port_fdb(struct rocker_port *rocker_port,
+			   const unsigned char *addr,
+			   __be16 vlan_id, int flags);
+
+static int rocker_event_mac_vlan_seen(struct rocker *rocker,
+				      const struct rocker_tlv *info)
+{
+	struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
+	unsigned int port_number;
+	struct rocker_port *rocker_port;
+	unsigned char *addr;
+	int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
+	__be16 vlan_id;
+
+	rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
+	if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_LPORT] ||
+	    !attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC] ||
+	    !attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID])
+		return -EIO;
+	port_number =
+		rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_MAC_VLAN_LPORT]) - 1;
+	addr = rocker_tlv_data(attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC]);
+	vlan_id = rocker_tlv_get_u16(attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID]);
+
+	if (port_number >= rocker->port_count)
+		return -EINVAL;
+
+	rocker_port = rocker->ports[port_number];
+
+	if (rocker_port->stp_state != BR_STATE_LEARNING &&
+	    rocker_port->stp_state != BR_STATE_FORWARDING)
+		return 0;
+
+	return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+}
+
 static int rocker_event_process(struct rocker *rocker,
 				struct rocker_desc_info *desc_info)
 {
@@ -1320,6 +1373,8 @@ static int rocker_event_process(struct rocker *rocker,
 	switch (type) {
 	case ROCKER_TLV_EVENT_TYPE_LINK_CHANGED:
 		return rocker_event_link_change(rocker, info);
+	case ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN:
+		return rocker_event_mac_vlan_seen(rocker, info);
 	}
 
 	return -EOPNOTSUPP;
@@ -2546,6 +2601,104 @@ static int rocker_group_l2_flood(struct rocker_port *rocker_port,
 				       group_id);
 }
 
+static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
+					int flags, __be16 vlan_id)
+{
+	struct rocker_port *p;
+	struct rocker *rocker = rocker_port->rocker;
+	u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
+	u32 group_ids[rocker->port_count];
+	u8 group_count = 0;
+	int err;
+	int i;
+
+	/* Adjust the flood group for this VLAN.  The flood group
+	 * references an L2 interface group for each port in this
+	 * VLAN.
+	 */
+
+	for (i = 0; i < rocker->port_count; i++) {
+		p = rocker->ports[i];
+		if (!rocker_port_is_bridged(p))
+			continue;
+		if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
+			group_ids[group_count++] =
+				ROCKER_GROUP_L2_INTERFACE(vlan_id,
+							  p->lport);
+		}
+	}
+
+	/* If there are no bridged ports in this VLAN, we're done */
+	if (group_count == 0)
+		return 0;
+
+	err = rocker_group_l2_flood(rocker_port, flags, vlan_id,
+				    group_count, group_ids,
+				    group_id);
+	if (err)
+		netdev_err(rocker_port->dev,
+			   "Error (%d) port VLAN l2 flood group\n", err);
+
+	return err;
+}
+
+static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
+				      int flags, __be16 vlan_id,
+				      bool pop_vlan)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_port *p;
+	bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
+	u32 out_lport;
+	int ref = 0;
+	int err;
+	int i;
+
+	/* An L2 interface group for this port in this VLAN, but
+	 * only when port STP state is LEARNING|FORWARDING.
+	 */
+
+	if (rocker_port->stp_state == BR_STATE_LEARNING ||
+	    rocker_port->stp_state == BR_STATE_FORWARDING) {
+		out_lport = rocker_port->lport;
+		err = rocker_group_l2_interface(rocker_port, flags,
+						vlan_id, out_lport,
+						pop_vlan);
+		if (err) {
+			netdev_err(rocker_port->dev,
+				   "Error (%d) port VLAN l2 group for lport %d\n",
+				   err, out_lport);
+			return err;
+		}
+	}
+
+	/* An L2 interface group for this VLAN to CPU port.
+	 * Add when first port joins this VLAN and destroy when
+	 * last port leaves this VLAN.
+	 */
+
+	for (i = 0; i < rocker->port_count; i++) {
+		p = rocker->ports[i];
+		if (test_bit(ntohs(vlan_id), p->vlan_bitmap))
+			ref++;
+	}
+
+	if ((!adding || ref != 1) && (adding || ref != 0))
+		return 0;
+
+	out_lport = 0;
+	err = rocker_group_l2_interface(rocker_port, flags,
+					vlan_id, out_lport,
+					pop_vlan);
+	if (err) {
+		netdev_err(rocker_port->dev,
+			   "Error (%d) port VLAN l2 group for CPU port\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
 static struct rocker_ctrl {
 	const u8 *eth_dst;
 	const u8 *eth_dst_mask;
@@ -2624,6 +2777,30 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
 	return err;
 }
 
+static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
+					int flags, struct rocker_ctrl *ctrl,
+					__be16 vlan_id)
+{
+	enum rocker_of_dpa_table_id goto_tbl =
+		ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+	u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
+	u32 tunnel_id = 0;
+	int err;
+
+	if (!rocker_port_is_bridged(rocker_port))
+		return 0;
+
+	err = rocker_flow_tbl_bridge(rocker_port, flags,
+				     ctrl->eth_dst, ctrl->eth_dst_mask,
+				     vlan_id, tunnel_id,
+				     goto_tbl, group_id, ctrl->copy_to_cpu);
+
+	if (err)
+		netdev_err(rocker_port->dev, "Error (%d) ctrl FLOOD\n", err);
+
+	return err;
+}
+
 static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
 				      int flags, struct rocker_ctrl *ctrl,
 				      __be16 vlan_id)
@@ -2654,6 +2831,9 @@ static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port, int flags,
 	if (ctrl->acl)
 		return rocker_port_ctrl_vlan_acl(rocker_port, flags,
 						 ctrl, vlan_id);
+	if (ctrl->bridge)
+		return rocker_port_ctrl_vlan_bridge(rocker_port, flags,
+						    ctrl, vlan_id);
 
 	if (ctrl->term)
 		return rocker_port_ctrl_vlan_term(rocker_port, flags,
@@ -2698,6 +2878,64 @@ static int rocker_port_ctrl(struct rocker_port *rocker_port, int flags,
 	return err;
 }
 
+static int rocker_port_vlan(struct rocker_port *rocker_port, int flags,
+			    u16 vid)
+{
+	enum rocker_of_dpa_table_id goto_tbl =
+		ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+	u32 in_lport = rocker_port->lport;
+	__be16 vlan_id = htons(vid);
+	__be16 vlan_id_mask = htons(0xffff);
+	__be16 internal_vlan_id;
+	bool untagged;
+	bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
+	int err;
+
+	internal_vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, &untagged);
+
+	if (adding && test_and_set_bit(ntohs(internal_vlan_id),
+				       rocker_port->vlan_bitmap))
+			return 0; /* already added */
+	else if (!adding && !test_and_clear_bit(ntohs(internal_vlan_id),
+						rocker_port->vlan_bitmap))
+			return 0; /* already removed */
+
+	if (adding) {
+		err = rocker_port_ctrl_vlan_add(rocker_port, flags,
+						internal_vlan_id);
+		if (err) {
+			netdev_err(rocker_port->dev,
+				   "Error (%d) port ctrl vlan add\n", err);
+			return err;
+		}
+	}
+
+	err = rocker_port_vlan_l2_groups(rocker_port, flags,
+					 internal_vlan_id, untagged);
+	if (err) {
+		netdev_err(rocker_port->dev,
+			   "Error (%d) port VLAN l2 groups\n", err);
+		return err;
+	}
+
+	err = rocker_port_vlan_flood_group(rocker_port, flags,
+					   internal_vlan_id);
+	if (err) {
+		netdev_err(rocker_port->dev,
+			   "Error (%d) port VLAN l2 flood group\n", err);
+		return err;
+	}
+
+	err = rocker_flow_tbl_vlan(rocker_port, flags,
+				   in_lport, vlan_id, vlan_id_mask,
+				   goto_tbl, untagged, internal_vlan_id);
+	if (err)
+		netdev_err(rocker_port->dev,
+			   "Error (%d) port VLAN table\n", err);
+
+	return err;
+}
+
 static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
 {
 	enum rocker_of_dpa_table_id goto_tbl;
@@ -2723,6 +2961,158 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
 	return err;
 }
 
+struct rocker_fdb_learn_work {
+	struct work_struct work;
+	struct net_device *dev;
+	int flags;
+	u8 addr[ETH_ALEN];
+	u16 vid;
+};
+
+static void rocker_port_fdb_learn_work(struct work_struct *work)
+{
+	struct rocker_fdb_learn_work *lw =
+		container_of(work, struct rocker_fdb_learn_work, work);
+	bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE);
+	bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED);
+
+	if (learned & removing)
+		br_fdb_learn_del(lw->dev, lw->addr, lw->vid);
+	else if (learned & !removing)
+		br_fdb_learn_add(lw->dev, lw->addr, lw->vid);
+
+	kfree(work);
+}
+
+static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
+				 int flags, const u8 *addr, __be16 vlan_id)
+{
+	struct rocker_fdb_learn_work *lw;
+	enum rocker_of_dpa_table_id goto_tbl =
+		ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+	u32 out_lport = rocker_port->lport;
+	u32 tunnel_id = 0;
+	u32 group_id = ROCKER_GROUP_NONE;
+	bool copy_to_cpu = false;
+	int err;
+
+	if (rocker_port_is_bridged(rocker_port))
+		group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
+
+	err = rocker_flow_tbl_bridge(rocker_port, flags, addr, NULL,
+				     vlan_id, tunnel_id, goto_tbl,
+				     group_id, copy_to_cpu);
+	if (err)
+		return err;
+
+	if (!rocker_port_is_bridged(rocker_port))
+		return 0;
+
+	lw = kmalloc(sizeof(*lw), rocker_op_flags_gfp(flags));
+	if (!lw)
+		return -ENOMEM;
+
+	INIT_WORK(&lw->work, rocker_port_fdb_learn_work);
+
+	lw->dev = rocker_port->dev;
+	lw->flags = flags;
+	ether_addr_copy(lw->addr, addr);
+	lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id);
+
+	schedule_work(&lw->work);
+
+	return 0;
+}
+
+static struct rocker_fdb_tbl_entry *
+rocker_fdb_tbl_find(struct rocker *rocker, struct rocker_fdb_tbl_entry *match)
+{
+	struct rocker_fdb_tbl_entry *found;
+
+	hash_for_each_possible(rocker->fdb_tbl, found, entry, match->key_crc32)
+		if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
+			return found;
+
+	return NULL;
+}
+
+static int rocker_port_fdb(struct rocker_port *rocker_port,
+			   const unsigned char *addr,
+			   __be16 vlan_id, int flags)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_fdb_tbl_entry *fdb;
+	struct rocker_fdb_tbl_entry *found;
+	bool removing = (flags & ROCKER_OP_FLAG_REMOVE);
+	unsigned long lock_flags;
+
+	fdb = kzalloc(sizeof(*fdb), rocker_op_flags_gfp(flags));
+	if (!fdb)
+		return -ENOMEM;
+
+	fdb->learned = (flags & ROCKER_OP_FLAG_LEARNED);
+	fdb->key.lport = rocker_port->lport;
+	ether_addr_copy(fdb->key.addr, addr);
+	fdb->key.vlan_id = vlan_id;
+	fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
+
+	spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
+
+	found = rocker_fdb_tbl_find(rocker, fdb);
+
+	if (removing && found) {
+		kfree(fdb);
+		hash_del(&found->entry);
+	} else if (!removing && !found) {
+		hash_add(rocker->fdb_tbl, &fdb->entry, fdb->key_crc32);
+	}
+
+	spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
+
+	/* Check if adding and already exists, or removing and can't find */
+	if (!found != !removing) {
+		kfree(fdb);
+		return 0;
+	}
+
+	return rocker_port_fdb_learn(rocker_port, flags, addr, vlan_id);
+}
+
+static int rocker_port_fdb_flush(struct rocker_port *rocker_port)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_fdb_tbl_entry *found;
+	unsigned long lock_flags;
+	int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
+	struct hlist_node *tmp;
+	int bkt;
+	int err = 0;
+
+	if (rocker_port->stp_state == BR_STATE_LEARNING ||
+	    rocker_port->stp_state == BR_STATE_FORWARDING)
+		return 0;
+
+	spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
+
+	hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
+		if (found->key.lport != rocker_port->lport)
+			continue;
+		if (!found->learned)
+			continue;
+		err = rocker_port_fdb_learn(rocker_port, flags,
+					    found->key.addr,
+					    found->key.vlan_id);
+		if (err)
+			goto err_out;
+		hash_del(&found->entry);
+	}
+
+err_out:
+	spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
+
+	return err;
+}
+
 static int rocker_port_router_mac(struct rocker_port *rocker_port,
 				  int flags, __be16 vlan_id)
 {
@@ -2755,6 +3145,98 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
 	return err;
 }
 
+static int rocker_port_fwding(struct rocker_port *rocker_port)
+{
+	bool pop_vlan;
+	u32 out_lport;
+	__be16 vlan_id;
+	u16 vid;
+	int flags = ROCKER_OP_FLAG_NOWAIT;
+	int err;
+
+	/* Port will be forwarding-enabled if its STP state is LEARNING
+	 * or FORWARDING.  Traffic from CPU can still egress, regardless of
+	 * port STP state.  Use L2 interface group on port VLANs as a way
+	 * to toggle port forwarding: if forwarding is disabled, L2
+	 * interface group will not exist.
+	 */
+
+	if (rocker_port->stp_state != BR_STATE_LEARNING &&
+	    rocker_port->stp_state != BR_STATE_FORWARDING)
+		flags |= ROCKER_OP_FLAG_REMOVE;
+
+	out_lport = rocker_port->lport;
+	for (vid = 1; vid < VLAN_N_VID; vid++) {
+		if (!test_bit(vid, rocker_port->vlan_bitmap))
+			continue;
+		vlan_id = htons(vid);
+		pop_vlan = rocker_vlan_id_is_internal(vlan_id);
+		err = rocker_group_l2_interface(rocker_port, flags,
+						vlan_id, out_lport,
+						pop_vlan);
+		if (err) {
+			netdev_err(rocker_port->dev,
+				   "Error (%d) port VLAN l2 group for lport %d\n",
+				   err, out_lport);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int rocker_port_stp_update(struct net_device *dev, u8 state)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	bool want[ROCKER_CTRL_MAX] = { 0, };
+	int flags;
+	int err;
+	int i;
+
+	if (rocker_port->stp_state == state)
+		return 0;
+
+	rocker_port->stp_state = state;
+
+	switch (state) {
+	case BR_STATE_DISABLED:
+		/* port is completely disabled */
+		break;
+	case BR_STATE_LISTENING:
+	case BR_STATE_BLOCKING:
+		want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true;
+		break;
+	case BR_STATE_LEARNING:
+	case BR_STATE_FORWARDING:
+		want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true;
+		want[ROCKER_CTRL_IPV4_MCAST] = true;
+		want[ROCKER_CTRL_IPV6_MCAST] = true;
+		if (rocker_port_is_bridged(rocker_port))
+			want[ROCKER_CTRL_DFLT_BRIDGING] = true;
+		else
+			want[ROCKER_CTRL_LOCAL_ARP] = true;
+		break;
+	}
+
+	for (i = 0; i < ROCKER_CTRL_MAX; i++) {
+		if (want[i] != rocker_port->ctrls[i]) {
+			flags = ROCKER_OP_FLAG_NOWAIT |
+				(want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
+			err = rocker_port_ctrl(rocker_port, flags,
+					       &rocker_ctrls[i]);
+			if (err)
+				return err;
+			rocker_port->ctrls[i] = want[i];
+		}
+	}
+
+	err = rocker_port_fdb_flush(rocker_port);
+	if (err)
+		return err;
+
+	return rocker_port_fwding(rocker_port);
+}
+
 static struct rocker_internal_vlan_tbl_entry *
 rocker_internal_vlan_tbl_find(struct rocker *rocker, int ifindex)
 {
@@ -2847,6 +3329,8 @@ not_found:
 static int rocker_port_open(struct net_device *dev)
 {
 	struct rocker_port *rocker_port = netdev_priv(dev);
+	u8 stp_state = rocker_port_is_bridged(rocker_port) ?
+		BR_STATE_BLOCKING : BR_STATE_FORWARDING;
 	int err;
 
 	err = rocker_port_dma_rings_init(rocker_port);
@@ -2869,12 +3353,18 @@ static int rocker_port_open(struct net_device *dev)
 		goto err_request_rx_irq;
 	}
 
+	err = rocker_port_stp_update(dev, stp_state);
+	if (err)
+		goto err_stp_update;
+
 	napi_enable(&rocker_port->napi_tx);
 	napi_enable(&rocker_port->napi_rx);
 	rocker_port_set_enable(rocker_port, true);
 	netif_start_queue(dev);
 	return 0;
 
+err_stp_update:
+	free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
 err_request_rx_irq:
 	free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
 err_request_tx_irq:
@@ -2890,6 +3380,7 @@ static int rocker_port_stop(struct net_device *dev)
 	rocker_port_set_enable(rocker_port, false);
 	napi_disable(&rocker_port->napi_rx);
 	napi_disable(&rocker_port->napi_tx);
+	rocker_port_stp_update(dev, BR_STATE_DISABLED);
 	free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
 	free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
 	rocker_port_dma_rings_fini(rocker_port);
@@ -3034,6 +3525,33 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p)
 	return 0;
 }
 
+static int rocker_port_vlan_rx_add_vid(struct net_device *dev,
+				       __be16 proto, u16 vid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	int err;
+
+	err = rocker_port_vlan(rocker_port, 0, vid);
+	if (err)
+		return err;
+
+	return rocker_port_router_mac(rocker_port, 0, htons(vid));
+}
+
+static int rocker_port_vlan_rx_kill_vid(struct net_device *dev,
+					__be16 proto, u16 vid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	int err;
+
+	err = rocker_port_router_mac(rocker_port, ROCKER_OP_FLAG_REMOVE,
+				     htons(vid));
+	if (err)
+		return err;
+
+	return rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, vid);
+}
+
 static int rocker_port_sw_parent_id_get(struct net_device *dev,
 					struct netdev_phys_item_id *psid)
 {
@@ -3045,12 +3563,48 @@ static int rocker_port_sw_parent_id_get(struct net_device *dev,
 	return 0;
 }
 
+static int rocker_port_sw_port_fdb_add(struct net_device *dev,
+				       const unsigned char *addr, u16 vid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	__be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL);
+	int flags = 0;
+
+	if (!rocker_port_is_bridged(rocker_port))
+		return -EINVAL;
+
+	return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+}
+
+static int rocker_port_sw_port_fdb_del(struct net_device *dev,
+				       const unsigned char *addr, u16 vid)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	__be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, NULL);
+	int flags = ROCKER_OP_FLAG_REMOVE;
+
+	if (!rocker_port_is_bridged(rocker_port))
+		return -EINVAL;
+
+	return rocker_port_fdb(rocker_port, addr, vlan_id, flags);
+}
+
+static int rocker_port_sw_port_stp_update(struct net_device *dev, u8 state)
+{
+	return rocker_port_stp_update(dev, state);
+}
+
 static const struct net_device_ops rocker_port_netdev_ops = {
 	.ndo_open			= rocker_port_open,
 	.ndo_stop			= rocker_port_stop,
 	.ndo_start_xmit			= rocker_port_xmit,
 	.ndo_set_mac_address		= rocker_port_set_mac_address,
+	.ndo_vlan_rx_add_vid		= rocker_port_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid		= rocker_port_vlan_rx_kill_vid,
 	.ndo_sw_parent_id_get		= rocker_port_sw_parent_id_get,
+	.ndo_sw_port_fdb_add		= rocker_port_sw_port_fdb_add,
+	.ndo_sw_port_fdb_del		= rocker_port_sw_port_fdb_del,
+	.ndo_sw_port_stp_update		= rocker_port_sw_port_stp_update,
 };
 
 /********************
@@ -3500,17 +4054,121 @@ static struct pci_driver rocker_pci_driver = {
 	.remove		= rocker_remove,
 };
 
+/************************************
+ * Net device notifier event handler
+ ************************************/
+
+static bool rocker_port_dev_check(struct net_device *dev)
+{
+	return dev->netdev_ops == &rocker_port_netdev_ops;
+}
+
+static int rocker_port_bridge_join(struct rocker_port *rocker_port,
+				   struct net_device *bridge)
+{
+	int err;
+
+	rocker_port_internal_vlan_id_put(rocker_port,
+					 rocker_port->dev->ifindex);
+
+	rocker_port->bridge_dev = bridge;
+
+	/* Use bridge internal VLAN ID for untagged pkts */
+	err = rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, 0);
+	if (err)
+		return err;
+	rocker_port->internal_vlan_id =
+		rocker_port_internal_vlan_id_get(rocker_port,
+						 bridge->ifindex);
+	err = rocker_port_vlan(rocker_port, 0, 0);
+
+	return err;
+}
+
+static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
+{
+	int err;
+
+	rocker_port_internal_vlan_id_put(rocker_port,
+					 rocker_port->bridge_dev->ifindex);
+
+	rocker_port->bridge_dev = NULL;
+
+	/* Use port internal VLAN ID for untagged pkts */
+	err = rocker_port_vlan(rocker_port, ROCKER_OP_FLAG_REMOVE, 0);
+	if (err)
+		return err;
+	rocker_port->internal_vlan_id =
+		rocker_port_internal_vlan_id_get(rocker_port,
+						 rocker_port->dev->ifindex);
+	err = rocker_port_vlan(rocker_port, 0, 0);
+
+	return err;
+}
+
+static int rocker_port_master_changed(struct net_device *dev)
+{
+	struct rocker_port *rocker_port = netdev_priv(dev);
+	struct net_device *master = netdev_master_upper_dev_get(dev);
+	int err = 0;
+
+	if (master && master->rtnl_link_ops &&
+	    !strcmp(master->rtnl_link_ops->kind, "bridge"))
+		err = rocker_port_bridge_join(rocker_port, master);
+	else
+		err = rocker_port_bridge_leave(rocker_port);
+
+	return err;
+}
+
+static int rocker_netdevice_event(struct notifier_block *unused,
+				  unsigned long event, void *ptr)
+{
+	struct net_device *dev;
+	int err;
+
+	switch (event) {
+	case NETDEV_CHANGEUPPER:
+		dev = netdev_notifier_info_to_dev(ptr);
+		if (!rocker_port_dev_check(dev))
+			return NOTIFY_DONE;
+		err = rocker_port_master_changed(dev);
+		if (err)
+			netdev_warn(dev,
+				    "failed to reflect master change (err %d)\n",
+				    err);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block rocker_netdevice_nb __read_mostly = {
+	.notifier_call = rocker_netdevice_event,
+};
+
 /***********************
  * Module init and exit
  ***********************/
 
 static int __init rocker_module_init(void)
 {
-	return pci_register_driver(&rocker_pci_driver);
+	int err;
+
+	register_netdevice_notifier(&rocker_netdevice_nb);
+	err = pci_register_driver(&rocker_pci_driver);
+	if (err)
+		goto err_pci_register_driver;
+	return 0;
+
+err_pci_register_driver:
+	unregister_netdevice_notifier(&rocker_netdevice_nb);
+	return err;
 }
 
 static void __exit rocker_module_exit(void)
 {
+	unregister_netdevice_notifier(&rocker_netdevice_nb);
 	pci_unregister_driver(&rocker_pci_driver);
 }
 
Signature · 1 line
1.9.3
#69 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 7 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add L2 bridge offloading support to rocker driver. Here, the Linux bridge driver is used to collect swdev ports into a tagged (or untagged) VLAN bridge. The swdev will offload from the bridge driver the following L2 bridging functions:

Quoted 5 lines

- Learning of neighbor MAC addresses on VLAN X Learned mac/vlan is
installed in bridge FDB. (And removed when device unlearns mac/vlan). Learning must be turned off on each bridge port to disable the feature in the bridge driver.

I have quiet a few use cases where the above is a no-no. I dont want learning of any sort (we have a knob for that in the bridge). And i dont want learning in hardware to be reflected in software. Basically this is a policy decision. Introduce a knob to choose whether hardware learnt addresses should be reflected in software.

Have to run, but will comment when i get the time.

cheers,
jamal

author maintainer
#70 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 8 lines · Mon, Nov 10, 2014 at 04:53:07AM CET, [email protected] wrote:
Quoted 7 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add L2 bridge offloading support to rocker driver. Here, the Linux bridge driver is used to collect swdev ports into a tagged (or untagged) VLAN bridge. The swdev will offload from the bridge driver the following L2 bridging functions:

Quoted 8 lines
Quoted 5 lines

- Learning of neighbor MAC addresses on VLAN X Learned mac/vlan is
installed in bridge FDB. (And removed when device unlearns mac/vlan). Learning must be turned off on each bridge port to disable the feature in the bridge driver.

I have quiet a few use cases where the above is a no-no. I dont want learning of any sort (we have a knob for that in the bridge).

I would love to see your code. Please do share.

Quoted 3 lines

And i dont want learning in hardware to be reflected in software. Basically this is a policy decision. Introduce a knob to choose whether hardware learnt addresses should be reflected in software.

This can be easily done as a bridge option I believe. If you are ok with that, I will add a patch (either in re-post or as a follow-up)

Quoted 7 lines

Have to run, but will comment when i get the time.

cheers,
jamal

#71 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 18 lines · Jiri Pirko
Quoted 8 lines · Mon, Nov 10, 2014 at 04:53:07AM CET, [email protected] wrote:
Quoted 7 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add L2 bridge offloading support to rocker driver. Here, the Linux bridge driver is used to collect swdev ports into a tagged (or untagged) VLAN bridge. The swdev will offload from the bridge driver the following L2 bridging functions:

Quoted 8 lines
Quoted 5 lines

- Learning of neighbor MAC addresses on VLAN X Learned mac/vlan is
installed in bridge FDB. (And removed when device unlearns mac/vlan). Learning must be turned off on each bridge port to disable the feature in the bridge driver.

I have quiet a few use cases where the above is a no-no. I dont want learning of any sort (we have a knob for that in the bridge).

Quoted 8 lines

I would love to see your code. Please do share.

Quoted 3 lines

And i dont want learning in hardware to be reflected in software. Basically this is a policy decision. Introduce a knob to choose whether hardware learnt addresses should be reflected in software.

This can be easily done as a bridge option I believe. If you are ok with that, I will add a patch (either in re-post or as a follow-up)

An option will be nice.

Regards,
Nicolas

#72 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

In reply to Jamal Hadi Salim
Quoted 16 lines · Jamal Hadi Salim
Quoted 8 lines · Jiri Pirko

From: Scott Feldman <[email protected]>

Add L2 bridge offloading support to rocker driver. Here, the Linux bridge driver is used to collect swdev ports into a tagged (or untagged) VLAN bridge. The swdev will offload from the bridge driver the following L2 bridging functions:

Quoted 5 lines

- Learning of neighbor MAC addresses on VLAN X Learned mac/vlan is
installed in bridge FDB. (And removed when device unlearns mac/vlan). Learning must be turned off on each bridge port to disable the feature in the bridge driver.

Quoted 5 lines

I have quiet a few use cases where the above is a no-no. I dont want learning of any sort (we have a knob for that in the bridge). And i dont want learning in hardware to be reflected in software. Basically this is a policy decision. Introduce a knob to choose whether hardware learnt addresses should be reflected in software.

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Quoted 7 lines

Have to run, but will comment when i get the time.

cheers,
jamal

#73 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 11 lines · Scott Feldman

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Yes to making it a bit. But:
This is not *learning*. You are doing a *sync*.
Those are two different things.

Learning on/off exists today. It signals to the L2 whether you should learn or not.
I like the way fdb_add/del work with a flag which says it is the software and/or offloaded version. Please keep that semantic.
What you are doing above is letting the hardware learn then syncing to software. You need a different flag there. something like:

SYNC_HW_FDB (1<<1)

cheers,
jamal

#74 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 27 lines · Jamal Hadi Salim
Quoted 11 lines · Scott Feldman

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Yes to making it a bit. But:
This is not *learning*. You are doing a *sync*.
Those are two different things.

Learning on/off exists today. It signals to the L2 whether you should learn or not.
I like the way fdb_add/del work with a flag which says it is the software and/or offloaded version. Please keep that semantic.
What you are doing above is letting the hardware learn then syncing to software. You need a different flag there. something like:

Quoted 2 lines

SYNC_HW_FDB (1<<1)

And in any case, It seems like this policy should be per bridge or per switch chip...or per fdb.. entry (like the original fdb_add/del) and not a "port" flag.. ?

#75 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 29 lines · Roopa Prabhu
Quoted 28 lines · Jamal Hadi Salim
Quoted 11 lines · Scott Feldman

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Yes to making it a bit. But:
This is not *learning*. You are doing a *sync*.
Those are two different things.

Learning on/off exists today. It signals to the L2 whether you should learn or not.
I like the way fdb_add/del work with a flag which says it is the software and/or offloaded version. Please keep that semantic.
What you are doing above is letting the hardware learn then syncing to software. You need a different flag there. something like:

Quoted 5 lines
Quoted 2 lines

SYNC_HW_FDB (1<<1)

And in any case, It seems like this policy should be per bridge or per switch chip...or per fdb..
entry (like the original fdb_add/del) and not a "port" flag.. ?

Per-port gives more flexibility, and it looks like we can extend existing IFLA_BRPORT_LEARNING without much trouble.

I didn't follow the fdb_add/del comment? Isn't an fdb entry port-specific by nature? fdb entry = {port, mac, vlan} tuple.

#76 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 29 lines · Scott Feldman
Quoted 28 lines · Roopa Prabhu
Quoted 27 lines · Jamal Hadi Salim
Quoted 10 lines · Scott Feldman

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Yes to making it a bit. But:
This is not *learning*. You are doing a *sync*.
Those are two different things.

Learning on/off exists today. It signals to the L2 whether you should learn or not.
I like the way fdb_add/del work with a flag which says it is the software and/or offloaded version. Please keep that semantic.
What you are doing above is letting the hardware learn then syncing to software. You need a different flag there. something like:

SYNC_HW_FDB (1<<1)

Quoted 8 lines
Quoted 3 lines

And in any case, It seems like this policy should be per bridge or per switch chip...or per fdb..
entry (like the original fdb_add/del) and not a "port" flag.. ?

Per-port gives more flexibility, and it looks like we can extend existing IFLA_BRPORT_LEARNING without much trouble.

I didn't follow the fdb_add/del comment? Isn't an fdb entry port-specific by nature? fdb entry = {port, mac, vlan} tuple.

yes it is, But if i remember correctly, the api (ndo op) could indicate offload to hw (or nic in this case) by giving 'self'. And in those cases the netdev nic port represents the switch.
(Will be nice to check and confirm this though).

#77 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 11 lines · Roopa Prabhu
Quoted 4 lines · Scott Feldman
Quoted 2 lines · Roopa Prabhu
Quoted 1 line · Jamal Hadi Salim

On 11/10/14 03:46, Scott Feldman wrote:

yes it is, But if i remember correctly, the api (ndo op) could indicate offload to hw (or nic in this case)
by giving 'self'. And in those cases the netdev nic port represents the switch.
(Will be nice to check and confirm this though).

No, you are correct. You select to add to the bridge fdb or/and via the underlying brport fdb.

cheers,
jamal

#78 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 19 lines · Jamal Hadi Salim
Quoted 8 lines · Roopa Prabhu
Quoted 6 lines · Scott Feldman
Quoted 3 lines · Roopa Prabhu
Quoted 1 line · Jamal Hadi Salim
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line · Scott Feldman

yes it is, But if i remember correctly, the api (ndo op) could indicate offload to hw (or nic in this case)
by giving 'self'. And in those cases the netdev nic port represents the switch.
(Will be nice to check and confirm this though).

Quoted 2 lines

No, you are correct. You select to add to the bridge fdb or/and via the underlying brport fdb.

For swdev, I don't care for the model where each port has an fdb and the bridge has an fdb. The bridge's fdb lookup/learning/fwding is what we're offloading to HW, so it makes more sense from the driver and to the user to use one fdb, the bridge's fdb. So user types "bridge fdb show" and static fdbs installed on the bridge and learned fdbs synced from HW are represented. One table.

I view the existing ndo_fdb_add/del ops useful for devices working standalone without the bridge driver that have some HW fwding capabilities and need to manage their own fdb. For devices under bridge, let's use the bridge's fdb, at least for swdev.

Does this make sense? I hate to use a lot of "I"s in my sentences, but looks like I did exactly that in above, so take this as an opinion, within the scope of swdev.

-scott

#79 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

Quoted 10 lines · Scott Feldman

On Mon, Nov 10, 2014 at 9:27 AM, Jamal Hadi Salim <[email protected]> wrote:

For swdev, I don't care for the model where each port has an fdb and the bridge has an fdb. The bridge's fdb lookup/learning/fwding is what we're offloading to HW, so it makes more sense from the driver and to the user to use one fdb, the bridge's fdb. So user types "bridge fdb show" and static fdbs installed on the bridge and learned fdbs synced from HW are represented. One table.

side note:
I hope we'd be able to tell apart what is in hardware vs software and what has been synced up from hardware (assuming policy says we are allowed to sync things).
Yes, there is one fdb table per bridge - but each entry would say which brport is involved. So the reference point being a bridge point sounds reasonable to me. i.e
Any fdb entry whether in h/w or s/w would point to an egress brport *always*. Are you thinking there is only one possible bridge?
Caveat: a piece of hardware could have multiple virtual bridges. In what Ben showed on the $5 realtek, after boot up we just know which brports exist and nothing more.
We can then create a bridge and attach brport to each. This gets reflected into hardware on a per brport level (I think there was a field called FID?).
Constraint: Each brport connects only to one bridge.

Quoted 3 lines

I view the existing ndo_fdb_add/del ops useful for devices working standalone without the bridge driver that have some HW fwding capabilities and need to manage their own fdb.

As in offload said fdb?

Quoted 3 lines

For devices under
bridge, let's use the bridge's fdb, at least for swdev.

If the hardware can only do one bridge sure.

Quoted 1 line

Does this make sense?

not quiet for me but i may be missing something.

I hate to use a lot of "I"s in my sentences,

Quoted 3 lines

but looks like I did exactly that in above, so take this as an opinion, within the scope of swdev.

"I" is useful for expressing an opinion or an expectation of course ;->
As an example:
_I_ believe we should be able to define how {learning, flooding etc} and where {hw vs sw} things are to be installed or learnt-from. I have use cases where the controller makes all the decisions.
And i tried to provide my motivation in one of the meetings here:
https://linux.cumulusnetworks.com/offload-discussion-1/jamal-NFstatecaching.pdf

cheers,
jamal

#80 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

In reply to Scott Feldman
Quoted 5 lines · Scott Feldman

On Mon, Nov 10, 2014 at 6:12 AM, Roopa Prabhu <[email protected]> wrote:

Per-port gives more flexibility, and it looks like we can extend existing IFLA_BRPORT_LEARNING without much trouble.

I am thinking per port as well...
So we have hardware and/or software selection of per port:
fdb flooding control, fdb learning control,
stp controls, multicast controls
some of those weird vepa controls

This is why i thought all these could use a bit representation each. You have 32 bit flags and 32 bit selector.

cheers,
jamal

#81 lore raw

Re: [patch net-next v2 10/10] rocker: implement L2 bridge offloading

In reply to Jamal Hadi Salim
Quoted 27 lines · Jamal Hadi Salim
Quoted 11 lines · Scott Feldman

IFLA_BRPORT_LEARNING is u8 attr and we're only using lower bit to turn learning on/off. Maybe we can use another bit to indicate learning to be done in sw or hw. I don't think adding another bit would break existing iproute2.

LEARNING_ENABLED (1 << 0)
LEARNING_HW (1 << 1)

Would this work?

Yes to making it a bit. But:
This is not *learning*. You are doing a *sync*.
Those are two different things.

Learning on/off exists today. It signals to the L2 whether you should learn or not.
I like the way fdb_add/del work with a flag which says it is the software and/or offloaded version. Please keep that semantic.
What you are doing above is letting the hardware learn then syncing to software. You need a different flag there. something like:

Quoted 1 line

SYNC_HW_FDB (1<<1)

Agreed, that's more accurate. Thanks for the refinement.

Quoted 3 lines

cheers,
jamal

author maintainer
#82 lore raw

PATCH 1/1 bridge: rename fdb_*_hw to fdb_*_hw_addr to avoid confusion

In reply to Jiri Pirko

The current name might seem that this actually offloads the fdb entry to hw. So rename it to clearly present that this for hardware address addition/removal.

---
 net/bridge/br_fdb.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
net/bridge/br_fdb.c +7 -7
index e02d21b..3886f84 100644
@@ -91,7 +91,7 @@ static void fdb_rcu_free(struct rcu_head *head)
  * are then updated with the new information.
  * Called under RTNL.
  */
-static void fdb_add_hw(struct net_bridge *br, const unsigned char *addr)
+static void fdb_add_hw_addr(struct net_bridge *br, const unsigned char *addr)
 {
 	int err;
 	struct net_bridge_port *p;
@@ -119,7 +119,7 @@ undo:
  * the ports with needed information.
  * Called under RTNL.
  */
-static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
+static void fdb_del_hw_addr(struct net_bridge *br, const unsigned char *addr)
 {
 	struct net_bridge_port *p;
 
@@ -134,7 +134,7 @@ static void fdb_del_hw(struct net_bridge *br, const unsigned char *addr)
 static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
 {
 	if (f->is_static) {
-		fdb_del_hw(br, f->addr.addr);
+		fdb_del_hw_addr(br, f->addr.addr);
 		if (f->dst)
 			netdev_sw_port_fdb_del(f->dst->dev,
 					       f->addr.addr, f->vlan_id);
@@ -519,7 +519,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 		return -ENOMEM;
 
 	fdb->is_local = fdb->is_static = 1;
-	fdb_add_hw(br, addr);
+	fdb_add_hw_addr(br, addr);
 	fdb_notify(br, fdb, RTM_NEWNEIGH);
 	return 0;
 }
@@ -759,21 +759,21 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
 			fdb->is_local = 1;
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
-				fdb_add_hw(br, addr);
+				fdb_add_hw_addr(br, addr);
 				netdev_sw_port_fdb_add(source->dev, addr, vid);
 			}
 		} else if (state & NUD_NOARP) {
 			fdb->is_local = 0;
 			if (!fdb->is_static) {
 				fdb->is_static = 1;
-				fdb_add_hw(br, addr);
+				fdb_add_hw_addr(br, addr);
 				netdev_sw_port_fdb_add(source->dev, addr, vid);
 			}
 		} else {
 			fdb->is_local = 0;
 			if (fdb->is_static) {
 				fdb->is_static = 0;
-				fdb_del_hw(br, addr);
+				fdb_del_hw_addr(br, addr);
 				netdev_sw_port_fdb_del(source->dev, addr, vid);
 			}
 		}
Signature · 1 line
1.9.3
maintainer
#83 lore raw

Re: [patch net-next] bridge: rename fdb_*_hw to fdb_*_hw_addr to avoid confusion

From: Jiri Pirko <[email protected]>
Date: Sun, 9 Nov 2014 17:40:16 +0100

Quoted 5 lines

The current name might seem that this actually offloads the fdb entry to hw. So rename it to clearly present that this for hardware address addition/removal.

This must have been relative to your rocket patch series because it doesn't apply cleanly.

I already am assuming that the rocket patch set is getting one more spin, so why don't you add this to that series?

Thanks.

author maintainer
#84 lore raw

Re: [patch net-next] bridge: rename fdb_*_hw to fdb_*_hw_addr to avoid confusion

Quoted 7 lines · Tue, Nov 11, 2014 at 03:33:06AM CET, [email protected] wrote:

From: Jiri Pirko <[email protected]>
Date: Sun, 9 Nov 2014 17:40:16 +0100

Quoted 4 lines

The current name might seem that this actually offloads the fdb entry to hw. So rename it to clearly present that this for hardware address addition/removal.

Quoted 7 lines
Quoted 1 line

This must have been relative to your rocket patch series because it doesn't apply cleanly.

I already am assuming that the rocket patch set is getting one more spin, so why don't you add this to that series?

Will do.

Quoted 2 lines

Thanks.

#85 lore raw
In reply to Jiri Pirko

Jiri,

I am hoping you have considered what Ben Lahaise's, John Fastabend's, and Roopa's patches after all those discussions and
meetings we have had (in which you promised you will merge patches in). I am not seeing much of that here or mention of anything of that sort.
At least please get their sign on - this is such an important piece of new work that you should make sure you get consensus. Otherwise we are back to square one and everyone is going their way with their patches;

Ben/Roopa/John - please issue either a signed-off as well if you agree with this approach otherwise i am hoping none of these patches are merged in.

I will look at the patches and comment.

cheers,
jamal

Quoted 81 lines · Jiri Pirko

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

So what this patchset includes:
- introduce switchdev api for implementing switch drivers (so far only linux bridge fdb offload is covered)
- introduce rocker switch driver which implements switchdev api

As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied.

For detailed description, please see individual patches.

v1->v2:
- addressed all DaveM's comments

Jiri Pirko (5):
net: rename netdev_phys_port_id to more generic name
net: introduce generic switch devices support
rtnl: expose physical switch id for particular device
net-sysfs: expose physical switch id for particular device
rocker: introduce rocker switch driver

Scott Feldman (5):
bridge: introduce fdb offloading via switchdev
bridge: call netdev_sw_port_stp_update when bridge port STP status
changes
bridge: add API to notify bridge driver of learned FBD on offloaded
device
rocker: implement rocker ofdpa flow table manipulation
rocker: implement L2 bridge offloading

  Documentation/networking/switchdev.txt           |   59 +
  MAINTAINERS                                      |   14 +
  drivers/net/ethernet/Kconfig                     |    1 +
  drivers/net/ethernet/Makefile                    |    1 +
  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 +-
  drivers/net/ethernet/rocker/Kconfig              |   27 +
  drivers/net/ethernet/rocker/Makefile             |    5 +
  drivers/net/ethernet/rocker/rocker.c             | 4182 ++++++++++++++++++++++
  drivers/net/ethernet/rocker/rocker.h             |  427 +++
  include/linux/if_bridge.h                        |   18 +
  include/linux/netdevice.h                        |   48 +-
  include/net/switchdev.h                          |   53 +
  include/uapi/linux/if_link.h                     |    1 +
  net/Kconfig                                      |    1 +
  net/Makefile                                     |    3 +
  net/bridge/br_fdb.c                              |   94 +-
  net/bridge/br_netlink.c                          |    2 +
  net/bridge/br_stp.c                              |    4 +
  net/bridge/br_stp_if.c                           |    3 +
  net/bridge/br_stp_timer.c                        |    2 +
  net/core/dev.c                                   |    2 +-
  net/core/net-sysfs.c                             |   26 +-
  net/core/rtnetlink.c                             |   30 +-
  net/switchdev/Kconfig                            |   13 +
  net/switchdev/Makefile                           |    5 +
  net/switchdev/switchdev.c                        |   93 +
  29 files changed, 5104 insertions(+), 18 deletions(-)

create mode 100644 Documentation/networking/switchdev.txt create mode 100644 drivers/net/ethernet/rocker/Kconfig create mode 100644 drivers/net/ethernet/rocker/Makefile create mode 100644 drivers/net/ethernet/rocker/rocker.c create mode 100644 drivers/net/ethernet/rocker/rocker.h 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

#86 lore raw

Hi Jamal, Hi Jiri,

On a somewhat related note I am also wondering what if any progress has been made regarding discussions of (and code for) the following:

1. Exposing flow tables to user-space
- I realise that this is Open vSwitch specific to some extent but I am in no way implying that it should be done instead of non-Open vSwitch specific work.
- Jiri, IIRC this was part ~v2 of your earlier offload patchset

2. Describing Switch Hardware
- I see John Fastabend moving forwards on this in his git repository
https://github.com/jrfastab/flow-net-next

The way that I see things is that both of the above could be exposed via netlink. And that the first at least could be backed by NDOs. As such I see this work as complementary and perhaps applying on top of this patchset. If I am mistaken in this regards it would be good to know :)

I am of course also interested to know if the above are moving forwards. To be clear I am very interested in being able to use these APIs to perform Open vSwitch offloads and I am very happy to help. (Jamal: I'm also interested in non-Open vSwitch offloads :)

Quoted 104 lines · Jamal Hadi Salim

Jiri,

I am hoping you have considered what Ben Lahaise's, John Fastabend's, and Roopa's patches after all those discussions and
meetings we have had (in which you promised you will merge patches in). I am not seeing much of that here or mention of anything of that sort.
At least please get their sign on - this is such an important piece of new work that you should make sure you get consensus. Otherwise we are back to square one and everyone is going their way with their patches;

Ben/Roopa/John - please issue either a signed-off as well if you agree with this approach otherwise i am hoping none of these patches are merged in.

I will look at the patches and comment.

cheers,
jamal

Quoted 81 lines · Jiri Pirko

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

So what this patchset includes:
- introduce switchdev api for implementing switch drivers (so far only linux bridge fdb offload is covered)
- introduce rocker switch driver which implements switchdev api

As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied.

For detailed description, please see individual patches.

v1->v2:
- addressed all DaveM's comments

Jiri Pirko (5):
net: rename netdev_phys_port_id to more generic name
net: introduce generic switch devices support
rtnl: expose physical switch id for particular device
net-sysfs: expose physical switch id for particular device
rocker: introduce rocker switch driver

Scott Feldman (5):
bridge: introduce fdb offloading via switchdev
bridge: call netdev_sw_port_stp_update when bridge port STP status
changes
bridge: add API to notify bridge driver of learned FBD on offloaded
device
rocker: implement rocker ofdpa flow table manipulation
rocker: implement L2 bridge offloading

 Documentation/networking/switchdev.txt           |   59 +
 MAINTAINERS                                      |   14 +
 drivers/net/ethernet/Kconfig                     |    1 +
 drivers/net/ethernet/Makefile                    |    1 +
 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 +-
 drivers/net/ethernet/rocker/Kconfig              |   27 +
 drivers/net/ethernet/rocker/Makefile             |    5 +
 drivers/net/ethernet/rocker/rocker.c             | 4182 ++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h             |  427 +++
 include/linux/if_bridge.h                        |   18 +
 include/linux/netdevice.h                        |   48 +-
 include/net/switchdev.h                          |   53 +
 include/uapi/linux/if_link.h                     |    1 +
 net/Kconfig                                      |    1 +
 net/Makefile                                     |    3 +
 net/bridge/br_fdb.c                              |   94 +-
 net/bridge/br_netlink.c                          |    2 +
 net/bridge/br_stp.c                              |    4 +
 net/bridge/br_stp_if.c                           |    3 +
 net/bridge/br_stp_timer.c                        |    2 +
 net/core/dev.c                                   |    2 +-
 net/core/net-sysfs.c                             |   26 +-
 net/core/rtnetlink.c                             |   30 +-
 net/switchdev/Kconfig                            |   13 +
 net/switchdev/Makefile                           |    5 +
 net/switchdev/switchdev.c                        |   93 +
 29 files changed, 5104 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/networking/switchdev.txt
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h
 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
#87 lore raw

Hi Simon,

Quoted 11 lines · Simon Horman

Hi Jamal, Hi Jiri,

On a somewhat related note I am also wondering what if any progress has been made regarding discussions of (and code for) the following:

1. Exposing flow tables to user-space
- I realise that this is Open vSwitch specific to some extent but I am in no way implying that it should be done instead of non-Open vSwitch specific work.
- Jiri, IIRC this was part ~v2 of your earlier offload patchset

I dont know what Rocker crowd is doing; however, I know John F. has been doing some work which i have stared at and I was hoping to join in with Ben's effort and show tc flow offload on the realtek chip in my infinite spare time unles. (for both Linux bridge and ports).
The priority is to merge the obvious bits first.

Quoted 9 lines

2. Describing Switch Hardware
- I see John Fastabend moving forwards on this in his git repository
https://github.com/jrfastab/flow-net-next

The way that I see things is that both of the above could be exposed via netlink. And that the first at least could be backed by NDOs. As such I see this work as complementary and perhaps applying on top of this patchset. If I am mistaken in this regards it would be good to know :)

You are correct - I will let John speak on his work, but that is the intent.
The challenge is there are many schools of thoughts and i am hoping it is not an arms race.

Quoted 5 lines

I am of course also interested to know if the above are moving forwards. To be clear I am very interested in being able to use these APIs to perform Open vSwitch offloads and I am very happy to help. (Jamal: I'm also interested in non-Open vSwitch offloads :)

Hey, OVS should be able to use these APIs; i am just interested in making sure they are not just for OVS or OF. Then we are all happy;->

cheers,
jamal

#88 lore raw
Quoted 15 lines · Jamal Hadi Salim

Hi Simon,

Quoted 11 lines · Simon Horman

Hi Jamal, Hi Jiri,

On a somewhat related note I am also wondering what if any progress has been made regarding discussions of (and code for) the following:

1. Exposing flow tables to user-space
- I realise that this is Open vSwitch specific to some extent but I am in no way implying that it should be done instead of non-Open vSwitch specific work.
- Jiri, IIRC this was part ~v2 of your earlier offload patchset

Quoted 6 lines

I dont know what Rocker crowd is doing; however, I know John F. has been doing some work which i have stared at and I was hoping to join in with Ben's effort and show tc flow offload on the realtek chip in my infinite spare time unles. (for both Linux bridge and ports).
The priority is to merge the obvious bits first.

Merging the obvious bits first is quite fine my me.

Quoted 10 lines
Quoted 9 lines

2. Describing Switch Hardware
- I see John Fastabend moving forwards on this in his git repository
https://github.com/jrfastab/flow-net-next

The way that I see things is that both of the above could be exposed via netlink. And that the first at least could be backed by NDOs. As such I see this work as complementary and perhaps applying on top of this patchset. If I am mistaken in this regards it would be good to know :)

Quoted 4 lines

You are correct - I will let John speak on his work, but that is the intent.
The challenge is there are many schools of thoughts and i am hoping it is not an arms race.

That is also my hope.

Quoted 8 lines
Quoted 5 lines

I am of course also interested to know if the above are moving forwards. To be clear I am very interested in being able to use these APIs to perform Open vSwitch offloads and I am very happy to help. (Jamal: I'm also interested in non-Open vSwitch offloads :)

Hey, OVS should be able to use these APIs; i am just interested in making sure they are not just for OVS or OF. Then we are all happy;->

I think we are all happy :)

#89 lore raw
Quoted 16 lines · Simon Horman
Quoted 15 lines · Jamal Hadi Salim

Hi Simon,

Quoted 11 lines · Simon Horman

Hi Jamal, Hi Jiri,

On a somewhat related note I am also wondering what if any progress has been made regarding discussions of (and code for) the following:

1. Exposing flow tables to user-space
- I realise that this is Open vSwitch specific to some extent but I am in no way implying that it should be done instead of non-Open vSwitch specific work.
- Jiri, IIRC this was part ~v2 of your earlier offload patchset

Quoted 9 lines
Quoted 6 lines

I dont know what Rocker crowd is doing; however, I know John F. has been doing some work which i have stared at and I was hoping to join in with Ben's effort and show tc flow offload on the realtek chip in my infinite spare time unles. (for both Linux bridge and ports).
The priority is to merge the obvious bits first.

Merging the obvious bits first is quite fine my me.

+1

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

2. Describing Switch Hardware
- I see John Fastabend moving forwards on this in his git repository
https://github.com/jrfastab/flow-net-next

The way that I see things is that both of the above could be exposed via netlink. And that the first at least could be backed by NDOs. As such I see this work as complementary and perhaps applying on top of this patchset. If I am mistaken in this regards it would be good to know :)

Quoted 6 lines
Quoted 4 lines

You are correct - I will let John speak on his work, but that is the intent.
The challenge is there are many schools of thoughts and i am hoping it is not an arms race.

That is also my hope.

My intent is to submit the Flow API bits once the base rocker switch gets committed. I've implemented the Flow API against ixgbe and a sadly a proprietary SDK. I'll implement it against the rocker switch as well.

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

I am of course also interested to know if the above are moving forwards. To be clear I am very interested in being able to use these APIs to perform Open vSwitch offloads and I am very happy to help. (Jamal: I'm also interested in non-Open vSwitch offloads :)

I think they are moving forward. I have some code cleanup to do on the flow API, but its mostly in place. Then I want to implement an example on Rocker switch so we could experiment with something why we wait for a real hardware driver. From my side assuming I at least got it close to correct should be doable in the next few week.

After that I want to work with Jesse/Jamal and look at integrating with OVS and other stacks. I thought a bit about the OVS integration path but I'll hold that discussion for the moment.

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Quoted 4 lines
Quoted 2 lines

Hey, OVS should be able to use these APIs; i am just interested in making sure they are not just for OVS or OF. Then we are all happy;->

I think we are all happy :)

I'm happy :) Also my intent is the flow API is more general then just OVS. My view is OVS should be one user of the API.

.John

Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
John Fastabend         Intel Corporation
#90 lore raw
Quoted 44 lines · John Fastabend
Quoted 16 lines · Simon Horman
Quoted 15 lines · Jamal Hadi Salim

Hi Simon,

Quoted 11 lines · Simon Horman

Hi Jamal, Hi Jiri,

On a somewhat related note I am also wondering what if any progress has been made regarding discussions of (and code for) the following:

1. Exposing flow tables to user-space
- I realise that this is Open vSwitch specific to some extent but I am in no way implying that it should be done instead of non-Open vSwitch specific work.
- Jiri, IIRC this was part ~v2 of your earlier offload patchset

Quoted 9 lines
Quoted 6 lines

I dont know what Rocker crowd is doing; however, I know John F. has been doing some work which i have stared at and I was hoping to join in with Ben's effort and show tc flow offload on the realtek chip in my infinite spare time unles. (for both Linux bridge and ports).
The priority is to merge the obvious bits first.

Merging the obvious bits first is quite fine my me.

+1

Quoted 15 lines
Quoted 14 lines
Quoted 9 lines

2. Describing Switch Hardware
- I see John Fastabend moving forwards on this in his git repository
https://github.com/jrfastab/flow-net-next

The way that I see things is that both of the above could be exposed via netlink. And that the first at least could be backed by NDOs. As such I see this work as complementary and perhaps applying on top of this patchset. If I am mistaken in this regards it would be good to know :)

You are correct - I will let John speak on his work, but that is the intent.
The challenge is there are many schools of thoughts and i am hoping it is not an arms race.

Quoted 6 lines
Quoted 1 line

That is also my hope.

My intent is to submit the Flow API bits once the base rocker switch gets committed. I've implemented the Flow API against ixgbe and a sadly a proprietary SDK. I'll implement it against the rocker switch as well.

Understood, that seems like a good approach to me.

Quoted 13 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

I am of course also interested to know if the above are moving forwards. To be clear I am very interested in being able to use these APIs to perform Open vSwitch offloads and I am very happy to help. (Jamal: I'm also interested in non-Open vSwitch offloads :)

I think they are moving forward. I have some code cleanup to do on the flow API, but its mostly in place. Then I want to implement an example on Rocker switch so we could experiment with something why we wait for a real hardware driver. From my side assuming I at least got it close to correct should be doable in the next few week.

Quoted 3 lines

After that I want to work with Jesse/Jamal and look at integrating with OVS and other stacks. I thought a bit about the OVS integration path but I'll hold that discussion for the moment.

I am looking forward to that discussion.

Quoted 4 lines

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Sure, will do. I took a look over your code about two weeks ago but I believe you have made some updates since then.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Hey, OVS should be able to use these APIs; i am just interested in making sure they are not just for OVS or OF. Then we are all happy;->

I think we are all happy :)

I'm happy :) Also my intent is the flow API is more general then just OVS. My view is OVS should be one user of the API.

I agree entirely.

#91 lore raw
In reply to John Fastabend

[snip]

Quoted 4 lines

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Hi John,

here is some preliminary feedback:

* I notice that the parse graph code isn't present yet. I suppose this is a difficult piece that naturally follows many other piece. None the less it is possibly the piece of most interest to me :-)

* Will del and update flows require flows to already exist? And similarly, will add flow require flows with the same match to not already exist? If so, the error handling seems tricky of more than one flow is to be deleted/updated. IIRC there was some discussion of that kind of issue at the (double) round table discussion on the last day of LPC14 in Düsseldorf.

* Should the .node_count value of ixgbe_table_node_l2 be 3? ixgbe_table_graph_nodes has three elements but perhaps you are intentionally excluding the last element ixgbe_table_node_nil?

#92 lore raw
Quoted 7 lines · Simon Horman

[snip]

Quoted 4 lines

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Quoted 8 lines

Hi John,

here is some preliminary feedback:

* I notice that the parse graph code isn't present yet. I suppose this is a difficult piece that naturally follows many other piece. None the less it is possibly the piece of most interest to me :-)

I can add this over the next few days. Also I wanted to publish some more complex examples on top of rocker switch. The nic drivers are interesting but not as complex as some of the switch devices.

There is also the table graph layout which I wanted tweak a bit. At the moment I have hardware that can run tables in parallel and some that executes tables in sequence. It might not be clear from the code (why I need the cleanup) but the source id is being used to indicate if the tables are executed in parallel or not.

Quoted 7 lines

* Will del and update flows require flows to already exist? And similarly, will add flow require flows with the same match to not already exist? If so, the error handling seems tricky of more than one flow is to be deleted/updated. IIRC there was some discussion of that kind of issue at the (double) round table discussion on the last day of LPC14 in Düsseldorf.

I would expect del/updates for flows that don't exist should fail.

I didn't intend to add any checks in the kernel to verify the matches are unique. My opinion on this is that user space shouldn't add new duplicate flows. And if it does hardware resources will be wasted.

Quoted 5 lines

* Should the .node_count value of ixgbe_table_node_l2 be 3? ixgbe_table_graph_nodes has three elements but perhaps you are intentionally excluding the last element ixgbe_table_node_nil?

Actually I could just drop the node_count at the moment because I've been null terminating the arrays with null items.

I should either add a count field to all the structures or null terminate the arrays. For now I mostly null terminate the arrays when I use them. For example matches is null terminates same for actions.

.John

#93 lore raw

Hi John,

Quoted 12 lines · John Fastabend
Quoted 11 lines · Simon Horman

[snip]

Quoted 4 lines

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Hi John,

here is some preliminary feedback:

Quoted 8 lines
Quoted 4 lines

* I notice that the parse graph code isn't present yet. I suppose this is a difficult piece that naturally follows many other piece. None the less it is possibly the piece of most interest to me :-)

I can add this over the next few days. Also I wanted to publish some more complex examples on top of rocker switch. The nic drivers are interesting but not as complex as some of the switch devices.

I see that you have added the header graph, which seems pretty nice from my reading so far.

It seems to allow for arbitrary connections between instances of net_flow_header_node, including I loops I suppose. This seems nice and flexible to me.

I have a very minor update to contribute which helped me to read the code. Please feel free to squash/ignore/...

drivers/net/ethernet/intel/ixgbe/ixgbe_pipeline.h +2 -2
index a4818ab..4025a61 100644
@@ -412,7 +412,7 @@ struct net_flow_jump_table ixgbe_vlan_inner_jump[2] = {
 		   .type = NET_FLOW_FIELD_REF_ATTR_TYPE_U16,
 		   .value_u16 = 0x0800,
 		},
-		.node = 4,
+		.node = HEADER_INSTANCE_IP,
 	},
 	{
 		.field = {0},
@@ -443,7 +443,7 @@ struct net_flow_jump_table ixgbe_ip_jump[2] = {
 		   .type = NET_FLOW_FIELD_REF_ATTR_TYPE_U8,
 		   .value_u8 = 0x06,
 		},
-		.node = 5,
+		.node = HEADER_INSTANCE_TCP,
 	},
 	{
 		.field = {0},
Quoted 5 lines

There is also the table graph layout which I wanted tweak a bit. At the moment I have hardware that can run tables in parallel and some that executes tables in sequence. It might not be clear from the code (why I need the cleanup) but the source id is being used to indicate if the tables are executed in parallel or not.

Thanks, that was not clear to me.

Quoted 8 lines
Quoted 6 lines

* Will del and update flows require flows to already exist? And similarly, will add flow require flows with the same match to not already exist? If so, the error handling seems tricky of more than one flow is to be deleted/updated. IIRC there was some discussion of that kind of issue at the (double) round table discussion on the last day of LPC14 in Düsseldorf.

I would expect del/updates for flows that don't exist should fail.

Am I right in thinking that del and update flow NDOs may take a list of flows? If so I think some consideration needs to be made for handling failure of e.g. the last element of the list when the previous elements succeeded.

I suppose that user-space could dump the flow table if an error and adjust its state accordingly. But that seems somewhat onerous.

Quoted 3 lines

I didn't intend to add any checks in the kernel to verify the matches are unique. My opinion on this is that user space shouldn't add new duplicate flows. And if it does hardware resources will be wasted.

I don't have any strong opinions on that at this time. But it does seem reasonable so long as its clear that is the case.

Quoted 11 lines
Quoted 4 lines

* Should the .node_count value of ixgbe_table_node_l2 be 3? ixgbe_table_graph_nodes has three elements but perhaps you are intentionally excluding the last element ixgbe_table_node_nil?

Actually I could just drop the node_count at the moment because I've been null terminating the arrays with null items.

I should either add a count field to all the structures or null terminate the arrays. For now I mostly null terminate the arrays when I use them. For example matches is null terminates same for actions.

It looks like you have move towards the null termination option. No objections here.

#94 lore raw
Quoted 20 lines · Simon Horman

Hi John,

Quoted 17 lines · John Fastabend
Quoted 15 lines · Simon Horman

[snip]

Quoted 4 lines

Simon, if your feeling adventurous any feedback on the repo link would be great. I still need to smash the commit log into something coherent though at the moment you can see all the errors and rewrites, etc as I made them.

Hi John,

here is some preliminary feedback:

* I notice that the parse graph code isn't present yet. I suppose this is a difficult piece that naturally follows many other piece. None the less it is possibly the piece of most interest to me :-)

Quoted 6 lines
Quoted 3 lines

I can add this over the next few days. Also I wanted to publish some more complex examples on top of rocker switch. The nic drivers are interesting but not as complex as some of the switch devices.

I see that you have added the header graph, which seems pretty nice from my reading so far.

Great. I'm iterating over some other hardware now to be sure it will work on some more complex configurations. And about ready to start the rocker implementation.

Quoted 4 lines

It seems to allow for arbitrary connections between instances of net_flow_header_node, including I loops I suppose. This seems nice and flexible to me.

Right loops could be supported.

Quoted 4 lines

I have a very minor update to contribute which helped me to read the code. Please feel free to squash/ignore/...

I like the patch. This sort of cleanup is needed.

Quoted 38 lines
drivers/net/ethernet/intel/ixgbe/ixgbe_pipeline.h +2 -2
index a4818ab..4025a61 100644
@@ -412,7 +412,7 @@ struct net_flow_jump_table ixgbe_vlan_inner_jump[2] = {
 		   .type = NET_FLOW_FIELD_REF_ATTR_TYPE_U16,
 		   .value_u16 = 0x0800,
 		},
-		.node = 4,
+		.node = HEADER_INSTANCE_IP,
 	},
 	{
 		.field = {0},
@@ -443,7 +443,7 @@ struct net_flow_jump_table ixgbe_ip_jump[2] = {
 		   .type = NET_FLOW_FIELD_REF_ATTR_TYPE_U8,
 		   .value_u8 = 0x06,
 		},
-		.node = 5,
+		.node = HEADER_INSTANCE_TCP,
 	},
 	{
 		.field = {0},
Quoted 6 lines

There is also the table graph layout which I wanted tweak a bit. At the moment I have hardware that can run tables in parallel and some that executes tables in sequence. It might not be clear from the code (why I need the cleanup) but the source id is being used to indicate if the tables are executed in parallel or not.

Thanks, that was not clear to me.

Quoted 7 lines
Quoted 6 lines

* Will del and update flows require flows to already exist? And similarly, will add flow require flows with the same match to not already exist? If so, the error handling seems tricky of more than one flow is to be deleted/updated. IIRC there was some discussion of that kind of issue at the (double) round table discussion on the last day of LPC14 in Düsseldorf.

Quoted 6 lines
Quoted 1 line

I would expect del/updates for flows that don't exist should fail.

Am I right in thinking that del and update flow NDOs may take a list of flows? If so I think some consideration needs to be made for handling failure of e.g. the last element of the list when the previous elements succeeded.

Yes the list of add/deletes are needed for user space to push down bulk commands. At init time or when management software resets or likely other cases we get large sets of rules being pushed down doing this in bulk is much better then one-offing the flow commands.

Quoted 3 lines

I suppose that user-space could dump the flow table if an error and adjust its state accordingly. But that seems somewhat onerous.

Right we talked about this briefly @ LPC if I recall correctly. I see a couple ways to do this. Either we do a best effort and return the first flow to have an error so userspace can learn where the failure occurred. Another option is to have the driver roll-back and remove any flows that were added leaving the driver in the same state it was before the add flow command started. Or we could support both and let user space tell us if we should use best effort or required modes.

Any thoughts?

Quoted 7 lines
Quoted 4 lines

I didn't intend to add any checks in the kernel to verify the matches are unique. My opinion on this is that user space shouldn't add new duplicate flows. And if it does hardware resources will be wasted.

I don't have any strong opinions on that at this time. But it does seem reasonable so long as its clear that is the case.

When I get to document this I'll call it out explicitly. I think we should have something in ./Documentation/networkin/ for this API.

Quoted 9 lines
Quoted 9 lines
Quoted 5 lines

* Should the .node_count value of ixgbe_table_node_l2 be 3? ixgbe_table_graph_nodes has three elements but perhaps you are intentionally excluding the last element ixgbe_table_node_nil?

Actually I could just drop the node_count at the moment because I've been null terminating the arrays with null items.

Quoted 7 lines
Quoted 3 lines

I should either add a count field to all the structures or null terminate the arrays. For now I mostly null terminate the arrays when I use them. For example matches is null terminates same for actions.

It looks like you have move towards the null termination option. No objections here.

yep, the code looked nicer to me at least with this approach.

Thanks for looking it over,
John

author maintainer
#95 lore raw
In reply to Jamal Hadi Salim
Quoted 7 lines · Mon, Nov 10, 2014 at 04:31:39AM CET, [email protected] wrote:

Jiri,

I am hoping you have considered what Ben Lahaise's, John Fastabend's, and Roopa's patches after all those discussions and meetings we have had (in which you promised you will merge patches in). I am not seeing much of that here or mention of anything of that sort.

Hi Jamal.

Yes I looked over their patches. Roopas patche's are about new class of device which, as I commented in the cover letter, I left out for now and can be safely added later on.

I went over the Ben's work very carefully as well. The patches are very rough, mostly rtl-chip specific. But again, my patchset is a base on which this patches can be build on. I see no issues in that.

Quoted 2 lines

At least please get their sign on - this is such an important piece of new work that you should make sure you get consensus.

Since I did not use their code now, I only put sign off of Scott.

Quoted 2 lines

Otherwise we are back to square one and everyone is going their way with their patches;

I do think that we are in sync. I do not see any counter ways. As I said, their work can be added on to the base made of this patchset.

Quoted 93 lines

Ben/Roopa/John - please issue either a signed-off as well if you agree with this approach otherwise i am hoping none of these patches are merged in.

I will look at the patches and comment.

cheers,
jamal

Quoted 81 lines · Jiri Pirko

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

So what this patchset includes:
- introduce switchdev api for implementing switch drivers (so far only linux bridge fdb offload is covered)
- introduce rocker switch driver which implements switchdev api

As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied.

For detailed description, please see individual patches.

v1->v2:
- addressed all DaveM's comments

Jiri Pirko (5):
net: rename netdev_phys_port_id to more generic name
net: introduce generic switch devices support
rtnl: expose physical switch id for particular device
net-sysfs: expose physical switch id for particular device
rocker: introduce rocker switch driver

Scott Feldman (5):
bridge: introduce fdb offloading via switchdev
bridge: call netdev_sw_port_stp_update when bridge port STP status
changes
bridge: add API to notify bridge driver of learned FBD on offloaded
device
rocker: implement rocker ofdpa flow table manipulation
rocker: implement L2 bridge offloading

 Documentation/networking/switchdev.txt           |   59 +
 MAINTAINERS                                      |   14 +
 drivers/net/ethernet/Kconfig                     |    1 +
 drivers/net/ethernet/Makefile                    |    1 +
 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 +-
 drivers/net/ethernet/rocker/Kconfig              |   27 +
 drivers/net/ethernet/rocker/Makefile             |    5 +
 drivers/net/ethernet/rocker/rocker.c             | 4182 ++++++++++++++++++++++
 drivers/net/ethernet/rocker/rocker.h             |  427 +++
 include/linux/if_bridge.h                        |   18 +
 include/linux/netdevice.h                        |   48 +-
 include/net/switchdev.h                          |   53 +
 include/uapi/linux/if_link.h                     |    1 +
 net/Kconfig                                      |    1 +
 net/Makefile                                     |    3 +
 net/bridge/br_fdb.c                              |   94 +-
 net/bridge/br_netlink.c                          |    2 +
 net/bridge/br_stp.c                              |    4 +
 net/bridge/br_stp_if.c                           |    3 +
 net/bridge/br_stp_timer.c                        |    2 +
 net/core/dev.c                                   |    2 +-
 net/core/net-sysfs.c                             |   26 +-
 net/core/rtnetlink.c                             |   30 +-
 net/switchdev/Kconfig                            |   13 +
 net/switchdev/Makefile                           |    5 +
 net/switchdev/switchdev.c                        |   93 +
 29 files changed, 5104 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/networking/switchdev.txt
 create mode 100644 drivers/net/ethernet/rocker/Kconfig
 create mode 100644 drivers/net/ethernet/rocker/Makefile
 create mode 100644 drivers/net/ethernet/rocker/rocker.c
 create mode 100644 drivers/net/ethernet/rocker/rocker.h
 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
#96 lore raw
Quoted 5 lines · Jiri Pirko

Yes I looked over their patches. Roopas patche's are about new class of device which, as I commented in the cover letter, I left out for now and can be safely added later on.

Quoted 9 lines

I went over the Ben's work very carefully as well. The patches are very rough, mostly rtl-chip specific. But again, my patchset is a base on which this patches can be build on. I see no issues in that.

Quoted 2 lines

At least please get their sign on - this is such an important piece of new work that you should make sure you get consensus.

Since I did not use their code now, I only put sign off of Scott.

Your last comment was "i am going to merge the patches" ;-> At least send an email explaining your plan to people who have worked hard to cooperate with you or say it in the cover letter.

Quoted 6 lines
Quoted 2 lines

Otherwise we are back to square one and everyone is going their way with their patches;

I do think that we are in sync. I do not see any counter ways. As I said, their work can be added on to the base made of this patchset.

Ok, I hope so. I spoke for myself - it is important for this patches you get their sign-on in my opinion.

cheers,
jamal

author maintainer
#97 lore raw
Quoted 14 lines · Mon, Nov 10, 2014 at 01:16:16PM CET, [email protected] wrote:
Quoted 12 lines · Jiri Pirko

Yes I looked over their patches. Roopas patche's are about new class of device which, as I commented in the cover letter, I left out for now and can be safely added later on.

I went over the Ben's work very carefully as well. The patches are very rough, mostly rtl-chip specific. But again, my patchset is a base on which this patches can be build on. I see no issues in that.

Quoted 2 lines

At least please get their sign on - this is such an important piece of new work that you should make sure you get consensus.

Quoted 6 lines
Quoted 2 lines

Since I did not use their code now, I only put sign off of Scott.

Your last comment was "i am going to merge the patches" ;-> At least send an email explaining your plan to people who have worked hard to cooperate with you or say it in the cover letter.

Well I had feedback only from Roopa and we discussed it in following email thread. I never had any feedback from Ben. I only saw you pasting link to his git.

There's really nothing else to merge at the moment. I would love to went over patches and merge them into my tree if anyone sends them.

Quoted 14 lines
Quoted 7 lines
Quoted 3 lines

Otherwise we are back to square one and everyone is going their way with their patches;

I do think that we are in sync. I do not see any counter ways. As I said, their work can be added on to the base made of this patchset.

Ok, I hope so. I spoke for myself - it is important for this patches you get their sign-on in my opinion.

cheers,
jamal

Reviewed-by on the v2 series
#98 lore raw
In reply to Jiri Pirko
Quoted 5 lines · Jiri Pirko

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

Despite my comment on ndo_fdb_add() which I believe can be reconsidered later. I like this pach series a lot. Thanks for putting in so much work on this topic.

author maintainer
#99 lore raw
In reply to Jiri Pirko

Going to post v3 with the suggested changes included next Tue/Wed. Thank you all for review!

Quoted 84 lines · Sun, Nov 09, 2014 at 11:51:10AM CET, [email protected] wrote:

Hi all.

This patchset is just the first phase of switch and switch-ish device support api in kernel. Note that the api will extend (our complete work can be pulled from https://github.com/jpirko/net-next-rocker).

So what this patchset includes:
- introduce switchdev api for implementing switch drivers (so far only linux bridge fdb offload is covered)
- introduce rocker switch driver which implements switchdev api

As to the discussion if there is need to have specific class of device representing the switch itself, so far we found no need to introduce that. But we are generally ok with the idea and when the time comes and it will be needed, it can be easily introduced without any disturbance.

This patchset introduces switch id export through rtnetlink and sysfs, which is similar to what we have for port id in SR-IOV. I will send iproute2 patchset for showing the switch id for port netdevs once this is applied.

For detailed description, please see individual patches.

v1->v2:
- addressed all DaveM's comments

Jiri Pirko (5):
net: rename netdev_phys_port_id to more generic name
net: introduce generic switch devices support
rtnl: expose physical switch id for particular device
net-sysfs: expose physical switch id for particular device
rocker: introduce rocker switch driver

Scott Feldman (5):
bridge: introduce fdb offloading via switchdev
bridge: call netdev_sw_port_stp_update when bridge port STP status
changes
bridge: add API to notify bridge driver of learned FBD on offloaded
device
rocker: implement rocker ofdpa flow table manipulation
rocker: implement L2 bridge offloading

Documentation/networking/switchdev.txt           |   59 +
MAINTAINERS                                      |   14 +
drivers/net/ethernet/Kconfig                     |    1 +
drivers/net/ethernet/Makefile                    |    1 +
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 +-
drivers/net/ethernet/rocker/Kconfig              |   27 +
drivers/net/ethernet/rocker/Makefile             |    5 +
drivers/net/ethernet/rocker/rocker.c             | 4182 ++++++++++++++++++++++
drivers/net/ethernet/rocker/rocker.h             |  427 +++
include/linux/if_bridge.h                        |   18 +
include/linux/netdevice.h                        |   48 +-
include/net/switchdev.h                          |   53 +
include/uapi/linux/if_link.h                     |    1 +
net/Kconfig                                      |    1 +
net/Makefile                                     |    3 +
net/bridge/br_fdb.c                              |   94 +-
net/bridge/br_netlink.c                          |    2 +
net/bridge/br_stp.c                              |    4 +
net/bridge/br_stp_if.c                           |    3 +
net/bridge/br_stp_timer.c                        |    2 +
net/core/dev.c                                   |    2 +-
net/core/net-sysfs.c                             |   26 +-
net/core/rtnetlink.c                             |   30 +-
net/switchdev/Kconfig                            |   13 +
net/switchdev/Makefile                           |    5 +
net/switchdev/switchdev.c                        |   93 +
29 files changed, 5104 insertions(+), 18 deletions(-)

create mode 100644 Documentation/networking/switchdev.txt create mode 100644 drivers/net/ethernet/rocker/Kconfig create mode 100644 drivers/net/ethernet/rocker/Makefile create mode 100644 drivers/net/ethernet/rocker/rocker.c create mode 100644 drivers/net/ethernet/rocker/rocker.h 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

Signature · 1 line
1.9.3