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