|
@@ -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));
|