summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2017-02-09 10:28:43 +0100
committerDavid S. Miller <davem@davemloft.net>2017-02-10 11:32:13 -0500
commit4283bce5f8c2307d47313e0429e5f1357c43023d (patch)
tree763a4eac7acd2f91bca761230e3e612a1be1c99c
parent9aecce1c7d977e52759167a4916d71e80aaf5070 (diff)
downloadlinux-4283bce5f8c2307d47313e0429e5f1357c43023d.tar.gz
linux-4283bce5f8c2307d47313e0429e5f1357c43023d.tar.bz2
linux-4283bce5f8c2307d47313e0429e5f1357c43023d.zip
mlxsw: spectrum_router: Add support for route append
When a new route is appended, it's placed after existing routes sharing the same parameters (prefix, length, table ID, TOS and priority). While the device supports only one route with the same prefix and length in a single table, it's important to correctly place the appended route in the driver's cache, as when a route is deleted the next one is programmed into the device. Following the reception of an ENTRY_APPEND notification, resolve the FIB node corresponding to the prefix and length and correctly place the new entry in its entry list. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 7c55df919a07..d98f0396b0e8 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2105,14 +2105,38 @@ mlxsw_sp_fib4_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
return NULL;
}
+static int mlxsw_sp_fib4_node_list_append(struct mlxsw_sp_fib_entry *fib_entry,
+ struct mlxsw_sp_fib_entry *new_entry)
+{
+ struct mlxsw_sp_fib_node *fib_node;
+
+ if (WARN_ON(!fib_entry))
+ return -EINVAL;
+
+ fib_node = fib_entry->fib_node;
+ list_for_each_entry_from(fib_entry, &fib_node->entry_list, list) {
+ if (fib_entry->params.tb_id != new_entry->params.tb_id ||
+ fib_entry->params.tos != new_entry->params.tos ||
+ fib_entry->params.prio != new_entry->params.prio)
+ break;
+ }
+
+ list_add_tail(&new_entry->list, &fib_entry->list);
+ return 0;
+}
+
static int
mlxsw_sp_fib4_node_list_insert(struct mlxsw_sp_fib_node *fib_node,
- struct mlxsw_sp_fib_entry *new_entry)
+ struct mlxsw_sp_fib_entry *new_entry,
+ bool append)
{
struct mlxsw_sp_fib_entry *fib_entry;
fib_entry = mlxsw_sp_fib4_node_entry_find(fib_node, &new_entry->params);
+ if (append)
+ return mlxsw_sp_fib4_node_list_append(fib_entry, new_entry);
+
if (fib_entry) {
list_add_tail(&new_entry->list, &fib_entry->list);
} else {
@@ -2182,12 +2206,13 @@ mlxsw_sp_fib4_node_entry_del(struct mlxsw_sp *mlxsw_sp,
}
static int mlxsw_sp_fib4_node_entry_link(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fib_entry *fib_entry)
+ struct mlxsw_sp_fib_entry *fib_entry,
+ bool append)
{
struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
int err;
- err = mlxsw_sp_fib4_node_list_insert(fib_node, fib_entry);
+ err = mlxsw_sp_fib4_node_list_insert(fib_node, fib_entry, append);
if (err)
return err;
@@ -2217,7 +2242,8 @@ mlxsw_sp_fib4_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
static int
mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
- const struct fib_entry_notifier_info *fen_info)
+ const struct fib_entry_notifier_info *fen_info,
+ bool append)
{
struct mlxsw_sp_fib_entry *fib_entry;
struct mlxsw_sp_fib_node *fib_node;
@@ -2239,7 +2265,7 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
goto err_fib4_entry_create;
}
- err = mlxsw_sp_fib4_node_entry_link(mlxsw_sp, fib_entry);
+ err = mlxsw_sp_fib4_node_entry_link(mlxsw_sp, fib_entry, append);
if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
goto err_fib4_node_entry_link;
@@ -2453,13 +2479,17 @@ static void mlxsw_sp_router_fib_event_work(struct work_struct *work)
struct mlxsw_sp_fib_event_work *fib_work =
container_of(work, struct mlxsw_sp_fib_event_work, work);
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
+ bool append;
int err;
/* Protect internal structures from changes */
rtnl_lock();
switch (fib_work->event) {
+ case FIB_EVENT_ENTRY_APPEND: /* fall through */
case FIB_EVENT_ENTRY_ADD:
- err = mlxsw_sp_router_fib4_add(mlxsw_sp, &fib_work->fen_info);
+ append = fib_work->event == FIB_EVENT_ENTRY_APPEND;
+ err = mlxsw_sp_router_fib4_add(mlxsw_sp, &fib_work->fen_info,
+ append);
if (err)
mlxsw_sp_router_fib4_abort(mlxsw_sp);
fib_info_put(fib_work->fen_info.fi);
@@ -2503,6 +2533,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
fib_work->event = event;
switch (event) {
+ case FIB_EVENT_ENTRY_APPEND: /* fall through */
case FIB_EVENT_ENTRY_ADD: /* fall through */
case FIB_EVENT_ENTRY_DEL:
memcpy(&fib_work->fen_info, ptr, sizeof(fib_work->fen_info));