lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1443993949-3915-7-git-send-email-jiri@resnulli.us>
Date:	Sun,  4 Oct 2015 23:25:41 +0200
From:	Jiri Pirko <jiri@...nulli.us>
To:	netdev@...r.kernel.org
Cc:	davem@...emloft.net, sfeldma@...il.com, idosch@...lanox.com,
	eladr@...lanox.com, tgraf@...g.ch, ast@...mgrid.com
Subject: [patch net-next 06/14] rocker: introduce worlds infrastructure

From: Jiri Pirko <jiri@...lanox.com>

This is another step on the way to per-world clean cut. Introduce world
ops hooks which each world can implement in world-specific way.
Also introduce world infrastructure including function for port worlds
change.

Signed-off-by: Jiri Pirko <jiri@...lanox.com>
---
 drivers/net/ethernet/rocker/rocker.h      |  56 ++++
 drivers/net/ethernet/rocker/rocker_main.c | 508 +++++++++++++++++++++++++++++-
 2 files changed, 563 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 650caa0..d49bc5d 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -12,7 +12,11 @@
 #ifndef _ROCKER_H
 #define _ROCKER_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/netdevice.h>
+#include <net/neighbour.h>
+#include <net/switchdev.h>
 
 #include "rocker_hw.h"
 
@@ -24,4 +28,56 @@ struct rocker_desc_info {
 	dma_addr_t mapaddr;
 };
 
+struct rocker;
+struct rocker_port;
+
+struct rocker_world_ops {
+	const char *kind;
+	size_t priv_size;
+	size_t port_priv_size;
+	u8 mode;
+	int (*init)(struct rocker *rocker, void *priv);
+	void (*fini)(void *priv);
+	int (*port_init)(struct rocker_port *rocker_port, void *priv,
+			 void *port_priv);
+	void (*port_fini)(void *port_priv);
+	int (*port_open)(void *port_priv);
+	void (*port_stop)(void *port_priv);
+	int (*port_attr_stp_state_set)(void *port_priv, u8 state,
+				       struct switchdev_trans *trans);
+	int (*port_attr_bridge_flags_set)(void *port_priv,
+					  unsigned long brport_flags,
+					  struct switchdev_trans *trans);
+	int (*port_attr_bridge_flags_get)(void *port_priv,
+					  unsigned long *p_brport_flags);
+	int (*port_obj_vlan_add)(void *port_priv,
+				 const struct switchdev_obj_port_vlan *vlan,
+				 struct switchdev_trans *trans);
+	int (*port_obj_vlan_del)(void *port_priv,
+				 const struct switchdev_obj_port_vlan *vlan);
+	int (*port_obj_vlan_dump)(void *port_priv,
+				  struct switchdev_obj_port_vlan *vlan,
+				  switchdev_obj_dump_cb_t *cb);
+	int (*port_obj_fib4_add)(void *port_priv,
+				 const struct switchdev_obj_ipv4_fib *fib4,
+				 struct switchdev_trans *trans);
+	int (*port_obj_fib4_del)(void *port_priv,
+				 const struct switchdev_obj_ipv4_fib *fib4);
+	int (*port_obj_fdb_add)(void *port_priv,
+				const struct switchdev_obj_port_fdb *fdb,
+				struct switchdev_trans *trans);
+	int (*port_obj_fdb_del)(void *port_priv,
+				const struct switchdev_obj_port_fdb *fdb);
+	int (*port_obj_fdb_dump)(void *port_priv,
+				 struct switchdev_obj_port_fdb *fdb,
+				 switchdev_obj_dump_cb_t *cb);
+	int (*port_master_linked)(void *port_priv, struct net_device *master);
+	int (*port_master_unlinked)(void *port_priv, struct net_device *master);
+	int (*port_neigh_update)(void *port_priv, struct neighbour *n);
+	int (*port_neigh_destroy)(void *port_priv, struct neighbour *n);
+	int (*port_ev_mac_vlan_seen)(void *port_priv,
+				     const unsigned char *addr,
+				     __be16 vlan_id);
+};
+
 #endif
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
index 54d2f46..b9b3c9d 100644
--- a/drivers/net/ethernet/rocker/rocker_main.c
+++ b/drivers/net/ethernet/rocker/rocker_main.c
@@ -210,6 +210,8 @@ struct rocker_port {
 	struct net_device *dev;
 	struct net_device *bridge_dev;
 	struct rocker *rocker;
+	struct rocker_world *world;
+	void *world_port_priv;
 	unsigned int port_number;
 	u32 pport;
 	__be16 internal_vlan_id;
@@ -236,6 +238,7 @@ struct rocker {
 	spinlock_t cmd_ring_lock;		/* for cmd ring accesses */
 	struct rocker_dma_ring_info cmd_ring;
 	struct rocker_dma_ring_info event_ring;
+	struct list_head worlds;
 	DECLARE_HASHTABLE(flow_tbl, 16);
 	spinlock_t flow_tbl_lock;		/* for flow tbl accesses */
 	u64 flow_tbl_next_cookie;
@@ -1236,6 +1239,9 @@ static int rocker_port_fdb(struct rocker_port *rocker_port,
 			   struct switchdev_trans *trans,
 			   const unsigned char *addr,
 			   __be16 vlan_id, int flags);
+static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
+					      const unsigned char *addr,
+					      __be16 vlan_id);
 
 static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
 				      const struct rocker_tlv *info)
@@ -1246,6 +1252,7 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
 	const unsigned char *addr;
 	int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
 	__be16 vlan_id;
+	int err;
 
 	rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
 	if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||
@@ -1262,6 +1269,10 @@ static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
 
 	rocker_port = rocker->ports[port_number];
 
+	err = rocker_world_port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
+	if (err)
+		return err;
+
 	if (rocker_port->stp_state != BR_STATE_LEARNING &&
 	    rocker_port->stp_state != BR_STATE_FORWARDING)
 		return 0;
@@ -2155,6 +2166,416 @@ static int rocker_cmd_group_tbl_del(const struct rocker_port *rocker_port,
 	return 0;
 }
 
+/**********************
+ * Worlds manipulation
+ **********************/
+
+static struct rocker_world_ops *rocker_world_ops[] = {
+};
+
+#define ROCKER_WORLD_OPS_LEN ARRAY_SIZE(rocker_world_ops)
+
+static const struct rocker_world_ops *__rocker_world_ops_find(const char *kind)
+{
+	struct rocker_world_ops *ops;
+	int i;
+
+	for (i = 0; i < ROCKER_WORLD_OPS_LEN; i++) {
+		ops = rocker_world_ops[i];
+		if (!strcmp(ops->kind, kind))
+			return ops;
+	}
+	return NULL;
+}
+
+struct rocker_world {
+	struct list_head list;
+	const struct rocker_world_ops *ops;
+	unsigned int ref;
+	unsigned long priv[0];
+};
+
+static struct rocker_world *__rocker_world_find(struct rocker *rocker,
+						const struct rocker_world_ops *ops)
+{
+	struct rocker_world *world;
+
+	list_for_each_entry(world, &rocker->worlds, list) {
+		if (world->ops == ops)
+			return world;
+	}
+	return NULL;
+}
+
+static int rocker_world_init(struct rocker *rocker, struct rocker_world *world)
+{
+	if (!world->ops->init)
+		return 0;
+	return world->ops->init(rocker, world->priv);
+}
+
+static void rocker_world_fini(struct rocker *rocker, struct rocker_world *world)
+{
+	if (!world->ops->fini)
+		return;
+	return world->ops->fini(world->priv);
+}
+
+static int rocker_world_get(struct rocker_port *rocker_port,
+			    const struct rocker_world_ops *ops)
+{
+	struct rocker *rocker = rocker_port->rocker;
+	struct rocker_world *world = __rocker_world_find(rocker, ops);
+	int err;
+
+	if (world)
+		goto ref_inc;
+	world = kzalloc(sizeof(*world) + ops->priv_size, GFP_KERNEL);
+	if (!world)
+		return -ENOMEM;
+	world->ops = ops;
+
+	err = rocker_world_init(rocker, world);
+	if (err)
+		goto err_world_init;
+
+	list_add_tail(&world->list, &rocker->worlds);
+ref_inc:
+	world->ref++;
+	rocker_port->world = world;
+	return 0;
+
+err_world_init:
+	kfree(world);
+	return err;
+}
+
+static void rocker_world_put(struct rocker_port *rocker_port)
+{
+	struct rocker_world *world = rocker_port->world;
+	struct rocker *rocker = rocker_port->rocker;
+
+	world->ref--;
+	if (world->ref)
+		return;
+	list_del(&world->list);
+	rocker_world_fini(rocker, world);
+	kfree(world);
+	rocker_port->world = NULL;
+}
+
+static int rocker_world_port_init(struct rocker_port *rocker_port)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_init)
+		return 0;
+	return world->ops->port_init(rocker_port, world->priv,
+				     rocker_port->world_port_priv);
+}
+
+static void rocker_world_port_fini(struct rocker_port *rocker_port)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_fini)
+		return;
+	world->ops->port_fini(rocker_port->world_port_priv);
+}
+
+static int rocker_world_port_join(struct rocker_port *rocker_port,
+				  const struct rocker_world_ops *ops)
+{
+	int err;
+
+	err = rocker_world_get(rocker_port, ops);
+	if (err)
+		return err;
+	rocker_port->world_port_priv = kzalloc(ops->port_priv_size, GFP_KERNEL);
+	if (!rocker_port->world_port_priv) {
+		err = -ENOMEM;
+		goto err_alloc_port_priv;
+	}
+	err = rocker_cmd_set_port_settings_mode(rocker_port, ops->mode);
+	if (err)
+		goto err_set_mode;
+	err = rocker_world_port_init(rocker_port);
+	if (err)
+		goto err_port_init;
+	return 0;
+
+err_port_init:
+err_set_mode:
+	kfree(rocker_port->world_port_priv);
+err_alloc_port_priv:
+	rocker_world_put(rocker_port);
+	return err;
+}
+
+static void rocker_world_port_leave(struct rocker_port *rocker_port)
+{
+	rocker_world_port_fini(rocker_port);
+	kfree(rocker_port->world_port_priv);
+	rocker_world_put(rocker_port);
+}
+
+static int __rocker_port_change_world(struct rocker_port *rocker_port,
+				      const struct rocker_world_ops *ops)
+{
+	int err;
+
+	/* Check if mode was previously set and do cleanup if so */
+	if (rocker_port->world)
+		rocker_world_port_leave(rocker_port);
+	if (ops) {
+		err = rocker_world_port_join(rocker_port, ops);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int rocker_port_change_world(struct rocker_port *rocker_port,
+				    const char *kind)
+{
+	const struct rocker_world_ops *ops;
+	int err;
+
+	if (rocker_port->dev->flags & IFF_UP)
+		return -EBUSY;
+
+	if (rocker_port->world &&
+	    strcmp(rocker_port->world->ops->kind, kind) == 0) {
+		netdev_err(rocker_port->dev, "Unable to change to the same world the port is in\n");
+		return -EINVAL;
+	}
+
+	ops = __rocker_world_ops_find(kind);
+	if (!ops) {
+		netdev_err(rocker_port->dev, "World \"%s\" not found\n", kind);
+		return -EINVAL;
+	}
+
+	err = __rocker_port_change_world(rocker_port, ops);
+	if (err) {
+		netdev_err(rocker_port->dev, "Failed to change to world \"%s\"\n", kind);
+		return err;
+	}
+
+	netdev_info(rocker_port->dev, "World changed to \"%s\"\n", kind);
+	return 0;
+}
+
+static int rocker_world_port_open(struct rocker_port *rocker_port)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (world->ops->port_open)
+		return 0;
+	return world->ops->port_open(rocker_port->world_port_priv);
+}
+
+static void rocker_world_port_stop(struct rocker_port *rocker_port)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (world->ops->port_stop)
+		return;
+	world->ops->port_stop(rocker_port->world_port_priv);
+}
+
+static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port,
+						u8 state,
+						struct switchdev_trans *trans)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_attr_stp_state_set)
+		return 0;
+	return world->ops->port_attr_stp_state_set(rocker_port->world_port_priv,
+						   state, trans);
+}
+
+static int
+rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
+					unsigned long brport_flags,
+					struct switchdev_trans *trans)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_attr_bridge_flags_set)
+		return 0;
+	return world->ops->port_attr_bridge_flags_set(rocker_port->world_port_priv,
+						      brport_flags, trans);
+}
+
+static int
+rocker_world_port_attr_bridge_flags_get(const struct rocker_port *rocker_port,
+					unsigned long *p_brport_flags)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_attr_bridge_flags_get)
+		return 0;
+	return world->ops->port_attr_bridge_flags_get(rocker_port->world_port_priv,
+						      p_brport_flags);
+}
+
+static int
+rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port,
+			       const struct switchdev_obj_port_vlan *vlan,
+			       struct switchdev_trans *trans)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_vlan_add)
+		return 0;
+	return world->ops->port_obj_vlan_add(rocker_port->world_port_priv,
+					     vlan, trans);
+}
+
+static int
+rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port,
+			       const struct switchdev_obj_port_vlan *vlan)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_vlan_del)
+		return 0;
+	return world->ops->port_obj_vlan_del(rocker_port->world_port_priv,
+					     vlan);
+}
+
+static int
+rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port,
+				struct switchdev_obj_port_vlan *vlan,
+				switchdev_obj_dump_cb_t *cb)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_vlan_dump)
+		return 0;
+	return world->ops->port_obj_vlan_dump(rocker_port->world_port_priv,
+					      vlan, cb);
+}
+
+static int
+rocker_world_port_obj_fib4_add(struct rocker_port *rocker_port,
+			       const struct switchdev_obj_ipv4_fib *fib4,
+			       struct switchdev_trans *trans)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_fib4_add)
+		return 0;
+	return world->ops->port_obj_fib4_add(rocker_port->world_port_priv,
+					     fib4, trans);
+}
+
+static int
+rocker_world_port_obj_fib4_del(struct rocker_port *rocker_port,
+			       const struct switchdev_obj_ipv4_fib *fib4)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_fib4_del)
+		return 0;
+	return world->ops->port_obj_fib4_del(rocker_port->world_port_priv,
+					     fib4);
+}
+
+static int
+rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port,
+			      const struct switchdev_obj_port_fdb *fdb,
+			      struct switchdev_trans *trans)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_fdb_add)
+		return 0;
+	return world->ops->port_obj_fdb_add(rocker_port->world_port_priv,
+					    fdb, trans);
+}
+
+static int
+rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port,
+			      const struct switchdev_obj_port_fdb *fdb)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_fdb_del)
+		return 0;
+	return world->ops->port_obj_fdb_del(rocker_port->world_port_priv,
+					    fdb);
+}
+
+static int
+rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port,
+			       struct switchdev_obj_port_fdb *fdb,
+			       switchdev_obj_dump_cb_t *cb)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_obj_fdb_dump)
+		return 0;
+	return world->ops->port_obj_fdb_dump(rocker_port->world_port_priv,
+					     fdb, cb);
+}
+
+static int rocker_world_port_master_linked(struct rocker_port *rocker_port,
+					   struct net_device *master)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_master_linked)
+		return 0;
+	return world->ops->port_master_linked(rocker_port->world_port_priv,
+					      master);
+}
+
+static int rocker_world_port_master_unlinked(struct rocker_port *rocker_port,
+					     struct net_device *master)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_master_unlinked)
+		return 0;
+	return world->ops->port_master_unlinked(rocker_port->world_port_priv,
+						master);
+}
+
+static int rocker_world_port_neigh_update(struct rocker_port *rocker_port,
+					  struct neighbour *n)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_neigh_update)
+		return 0;
+	return world->ops->port_neigh_update(rocker_port->world_port_priv, n);
+}
+
+static int rocker_world_port_neigh_destroy(struct rocker_port *rocker_port,
+					   struct neighbour *n)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_neigh_destroy)
+		return 0;
+	return world->ops->port_neigh_destroy(rocker_port->world_port_priv, n);
+}
+
+static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
+					      const unsigned char *addr,
+					      __be16 vlan_id)
+{
+	struct rocker_world *world = rocker_port->world;
+
+	if (!world->ops->port_ev_mac_vlan_seen)
+		return 0;
+	return world->ops->port_ev_mac_vlan_seen(rocker_port->world_port_priv,
+						 addr, vlan_id);
+}
+
 /***************************************************
  * Flow, group, FDB, internal VLAN and neigh tables
  ***************************************************/
@@ -3849,6 +4270,11 @@ static int rocker_port_open(struct net_device *dev)
 	struct rocker_port *rocker_port = netdev_priv(dev);
 	int err;
 
+	if (!rocker_port->world) {
+		netdev_err(rocker_port->dev, "World not set\n");
+		return -EINVAL;
+	}
+
 	err = rocker_port_dma_rings_init(rocker_port);
 	if (err)
 		return err;
@@ -3869,6 +4295,12 @@ static int rocker_port_open(struct net_device *dev)
 		goto err_request_rx_irq;
 	}
 
+	err = rocker_world_port_open(rocker_port);
+	if (err) {
+		netdev_err(rocker_port->dev, "cannot open port in world\n");
+		goto err_world_port_open;
+	}
+
 	err = rocker_port_fwd_enable(rocker_port, NULL, 0);
 	if (err)
 		goto err_fwd_enable;
@@ -3881,6 +4313,7 @@ static int rocker_port_open(struct net_device *dev)
 	return 0;
 
 err_fwd_enable:
+err_world_port_open:
 	free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
 err_request_rx_irq:
 	free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
@@ -3897,6 +4330,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_world_port_stop(rocker_port);
 	rocker_port_fwd_disable(rocker_port, NULL,
 				ROCKER_OP_FLAG_NOWAIT);
 	free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
@@ -4107,9 +4541,14 @@ static void rocker_port_neigh_destroy(struct neighbour *n)
 	struct rocker_port *rocker_port = netdev_priv(n->dev);
 	int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
 	__be32 ip_addr = *(__be32 *)n->primary_key;
+	int err;
 
 	rocker_port_ipv4_neigh(rocker_port, NULL,
 			       flags, ip_addr, n->ha);
+	err = rocker_world_port_neigh_destroy(rocker_port, n);
+	if (err)
+		netdev_warn(rocker_port->dev, "failed to handle neigh destroy (err %d)\n",
+			    err);
 }
 
 static const struct net_device_ops rocker_port_netdev_ops = {
@@ -4138,6 +4577,7 @@ static int rocker_port_attr_get(struct net_device *dev,
 {
 	const struct rocker_port *rocker_port = netdev_priv(dev);
 	const struct rocker *rocker = rocker_port->rocker;
+	int err = 0;
 
 	switch (attr->id) {
 	case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
@@ -4146,12 +4586,14 @@ static int rocker_port_attr_get(struct net_device *dev,
 		break;
 	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
 		attr->u.brport_flags = rocker_port->brport_flags;
+		err = rocker_world_port_attr_bridge_flags_get(rocker_port,
+							      &attr->u.brport_flags);
 		break;
 	default:
 		return -EOPNOTSUPP;
 	}
 
-	return 0;
+	return err;
 }
 
 static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
@@ -4184,10 +4626,20 @@ static int rocker_port_attr_set(struct net_device *dev,
 		err = rocker_port_stp_update(rocker_port, trans,
 					     ROCKER_OP_FLAG_NOWAIT,
 					     attr->u.stp_state);
+		if (err)
+			break;
+		err = rocker_world_port_attr_stp_state_set(rocker_port,
+							   attr->u.stp_state,
+							   trans);
 		break;
 	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
 		err = rocker_port_brport_flags_set(rocker_port, trans,
 						   attr->u.brport_flags);
+		if (err)
+			break;
+		err = rocker_world_port_attr_bridge_flags_set(rocker_port,
+							      attr->u.brport_flags,
+							      trans);
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -4259,16 +4711,31 @@ static int rocker_port_obj_add(struct net_device *dev,
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = rocker_port_vlans_add(rocker_port, trans,
 					    SWITCHDEV_OBJ_PORT_VLAN(obj));
+		if (err)
+			break;
+		err = rocker_world_port_obj_vlan_add(rocker_port,
+						     SWITCHDEV_OBJ_PORT_VLAN(obj),
+						     trans);
 		break;
 	case SWITCHDEV_OBJ_ID_IPV4_FIB:
 		fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
 		err = rocker_port_fib_ipv4(rocker_port, trans,
 					   htonl(fib4->dst), fib4->dst_len,
 					   fib4->fi, fib4->tb_id, 0);
+		if (err)
+			break;
+		err = rocker_world_port_obj_fib4_add(rocker_port,
+						     SWITCHDEV_OBJ_IPV4_FIB(obj),
+						     trans);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
 		err = rocker_port_fdb_add(rocker_port, trans,
 					  SWITCHDEV_OBJ_PORT_FDB(obj));
+		if (err)
+			break;
+		err = rocker_world_port_obj_fdb_add(rocker_port,
+						    SWITCHDEV_OBJ_PORT_FDB(obj),
+						    trans);
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -4331,6 +4798,10 @@ static int rocker_port_obj_del(struct net_device *dev,
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = rocker_port_vlans_del(rocker_port,
 					    SWITCHDEV_OBJ_PORT_VLAN(obj));
+		if (err)
+			break;
+		err = rocker_world_port_obj_vlan_del(rocker_port,
+						     SWITCHDEV_OBJ_PORT_VLAN(obj));
 		break;
 	case SWITCHDEV_OBJ_ID_IPV4_FIB:
 		fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
@@ -4338,10 +4809,18 @@ static int rocker_port_obj_del(struct net_device *dev,
 					   htonl(fib4->dst), fib4->dst_len,
 					   fib4->fi, fib4->tb_id,
 					   ROCKER_OP_FLAG_REMOVE);
+		if (err)
+			break;
+		err = rocker_world_port_obj_fib4_del(rocker_port,
+						     SWITCHDEV_OBJ_IPV4_FIB(obj));
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
 		err = rocker_port_fdb_del(rocker_port, NULL,
 					  SWITCHDEV_OBJ_PORT_FDB(obj));
+		if (err)
+			break;
+		err = rocker_world_port_obj_fdb_del(rocker_port,
+						    SWITCHDEV_OBJ_PORT_FDB(obj));
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -4412,10 +4891,20 @@ static int rocker_port_obj_dump(struct net_device *dev,
 	case SWITCHDEV_OBJ_ID_PORT_FDB:
 		err = rocker_port_fdb_dump(rocker_port,
 					   SWITCHDEV_OBJ_PORT_FDB(obj), cb);
+		if (err)
+			break;
+		err = rocker_world_port_obj_fdb_dump(rocker_port,
+						     SWITCHDEV_OBJ_PORT_FDB(obj),
+						     cb);
 		break;
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 		err = rocker_port_vlan_dump(rocker_port,
 					    SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
+		if (err)
+			break;
+		err = rocker_world_port_obj_vlan_dump(rocker_port,
+						      SWITCHDEV_OBJ_PORT_VLAN(obj),
+						      cb);
 		break;
 	default:
 		err = -EOPNOTSUPP;
@@ -4910,6 +5399,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	rocker = kzalloc(sizeof(*rocker), GFP_KERNEL);
 	if (!rocker)
 		return -ENOMEM;
+	INIT_LIST_HEAD(&rocker->worlds);
 
 	err = pci_enable_device(pdev);
 	if (err) {
@@ -5187,12 +5677,22 @@ static int rocker_netdevice_event(struct notifier_block *unused,
 			goto out;
 		rocker_port = netdev_priv(dev);
 		if (info->linking) {
+			err = rocker_world_port_master_linked(rocker_port,
+							      info->upper_dev);
+			if (err)
+				netdev_warn(dev, "failed to reflect master linked (err %d)\n",
+					    err);
 			err = rocker_port_master_linked(rocker_port,
 							info->upper_dev);
 			if (err)
 				netdev_warn(dev, "failed to reflect master linked (err %d)\n",
 					    err);
 		} else {
+			err = rocker_world_port_master_unlinked(rocker_port,
+								info->upper_dev);
+			if (err)
+				netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
+					    err);
 			err = rocker_port_master_unlinked(rocker_port);
 			if (err)
 				netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
@@ -5225,6 +5725,7 @@ static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
 static int rocker_netevent_event(struct notifier_block *unused,
 				 unsigned long event, void *ptr)
 {
+	struct rocker_port *rocker_port;
 	struct net_device *dev;
 	struct neighbour *n = ptr;
 	int err;
@@ -5236,6 +5737,11 @@ static int rocker_netevent_event(struct notifier_block *unused,
 		dev = n->dev;
 		if (!rocker_port_dev_check(dev))
 			return NOTIFY_DONE;
+		rocker_port = netdev_priv(dev);
+		err = rocker_world_port_neigh_update(rocker_port, n);
+		if (err)
+			netdev_warn(dev, "failed to handle neigh update (err %d)\n",
+				    err);
 		err = rocker_neigh_update(dev, n);
 		if (err)
 			netdev_warn(dev,
-- 
1.9.3

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ