Commit eab9a2d5 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-IPv6-and-reference-counting-fixes'

Ido Schimmel says:

====================
mlxsw: IPv6 and reference counting fixes

The first three patches fix a mismatch between the new IPv6 behavior
introduced in commit f34436a4 ("net/ipv6: Simplify route replace and
appending into multipath route") and mlxsw. The patches allow the driver
to support multipathing in IPv6 overlays with GRE tunnel devices. A
selftest will be submitted when net-next opens.

The last patch fixes a reference count problem of the port_vlan struct.
I plan to simplify the code in net-next, so that reference counting is
not necessary anymore.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 41f9ba67 9e25826f
...@@ -4756,12 +4756,6 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6) ...@@ -4756,12 +4756,6 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
kfree(mlxsw_sp_rt6); kfree(mlxsw_sp_rt6);
} }
static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
{
/* RTF_CACHE routes are ignored */
return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
}
static struct fib6_info * static struct fib6_info *
mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry) mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
{ {
...@@ -4771,11 +4765,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry) ...@@ -4771,11 +4765,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
static struct mlxsw_sp_fib6_entry * static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
const struct fib6_info *nrt, bool replace) const struct fib6_info *nrt, bool append)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace) if (!append)
return NULL; return NULL;
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
...@@ -4790,8 +4784,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, ...@@ -4790,8 +4784,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
break; break;
if (rt->fib6_metric < nrt->fib6_metric) if (rt->fib6_metric < nrt->fib6_metric)
continue; continue;
if (rt->fib6_metric == nrt->fib6_metric && if (rt->fib6_metric == nrt->fib6_metric)
mlxsw_sp_fib6_rt_can_mp(rt))
return fib6_entry; return fib6_entry;
if (rt->fib6_metric > nrt->fib6_metric) if (rt->fib6_metric > nrt->fib6_metric)
break; break;
...@@ -5170,7 +5163,7 @@ static struct mlxsw_sp_fib6_entry * ...@@ -5170,7 +5163,7 @@ static struct mlxsw_sp_fib6_entry *
mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
const struct fib6_info *nrt, bool replace) const struct fib6_info *nrt, bool replace)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL; struct mlxsw_sp_fib6_entry *fib6_entry;
list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry); struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
...@@ -5179,18 +5172,13 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, ...@@ -5179,18 +5172,13 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
continue; continue;
if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id) if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
break; break;
if (replace && rt->fib6_metric == nrt->fib6_metric) { if (replace && rt->fib6_metric == nrt->fib6_metric)
if (mlxsw_sp_fib6_rt_can_mp(rt) == return fib6_entry;
mlxsw_sp_fib6_rt_can_mp(nrt))
return fib6_entry;
if (mlxsw_sp_fib6_rt_can_mp(nrt))
fallback = fallback ?: fib6_entry;
}
if (rt->fib6_metric > nrt->fib6_metric) if (rt->fib6_metric > nrt->fib6_metric)
return fallback ?: fib6_entry; return fib6_entry;
} }
return fallback; return NULL;
} }
static int static int
...@@ -5316,7 +5304,8 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp, ...@@ -5316,7 +5304,8 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp,
} }
static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
struct fib6_info *rt, bool replace) struct fib6_info *rt, bool replace,
bool append)
{ {
struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib6_entry *fib6_entry;
struct mlxsw_sp_fib_node *fib_node; struct mlxsw_sp_fib_node *fib_node;
...@@ -5342,7 +5331,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5342,7 +5331,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
/* Before creating a new entry, try to append route to an existing /* Before creating a new entry, try to append route to an existing
* multipath entry. * multipath entry.
*/ */
fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace); fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, append);
if (fib6_entry) { if (fib6_entry) {
err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt); err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt);
if (err) if (err)
...@@ -5350,6 +5339,14 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5350,6 +5339,14 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
return 0; return 0;
} }
/* We received an append event, yet did not find any route to
* append to.
*/
if (WARN_ON(append)) {
err = -EINVAL;
goto err_fib6_entry_append;
}
fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt); fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt);
if (IS_ERR(fib6_entry)) { if (IS_ERR(fib6_entry)) {
err = PTR_ERR(fib6_entry); err = PTR_ERR(fib6_entry);
...@@ -5367,6 +5364,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, ...@@ -5367,6 +5364,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
err_fib6_node_entry_link: err_fib6_node_entry_link:
mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
err_fib6_entry_create: err_fib6_entry_create:
err_fib6_entry_append:
err_fib6_entry_nexthop_add: err_fib6_entry_nexthop_add:
mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
return err; return err;
...@@ -5717,7 +5715,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) ...@@ -5717,7 +5715,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
struct mlxsw_sp_fib_event_work *fib_work = struct mlxsw_sp_fib_event_work *fib_work =
container_of(work, struct mlxsw_sp_fib_event_work, work); container_of(work, struct mlxsw_sp_fib_event_work, work);
struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
bool replace; bool replace, append;
int err; int err;
rtnl_lock(); rtnl_lock();
...@@ -5728,8 +5726,10 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) ...@@ -5728,8 +5726,10 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
case FIB_EVENT_ENTRY_APPEND: /* fall through */ case FIB_EVENT_ENTRY_APPEND: /* fall through */
case FIB_EVENT_ENTRY_ADD: case FIB_EVENT_ENTRY_ADD:
replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
append = fib_work->event == FIB_EVENT_ENTRY_APPEND;
err = mlxsw_sp_router_fib6_add(mlxsw_sp, err = mlxsw_sp_router_fib6_add(mlxsw_sp,
fib_work->fen6_info.rt, replace); fib_work->fen6_info.rt, replace,
append);
if (err) if (err)
mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_router_fib_abort(mlxsw_sp);
mlxsw_sp_rt6_release(fib_work->fen6_info.rt); mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
......
...@@ -1018,8 +1018,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, ...@@ -1018,8 +1018,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
int err; int err;
/* No need to continue if only VLAN flags were changed */ /* No need to continue if only VLAN flags were changed */
if (mlxsw_sp_port_vlan->bridge_port) if (mlxsw_sp_port_vlan->bridge_port) {
mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
return 0; return 0;
}
err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port);
if (err) if (err)
......
...@@ -934,6 +934,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -934,6 +934,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
{ {
struct fib6_info *leaf = rcu_dereference_protected(fn->leaf, struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
lockdep_is_held(&rt->fib6_table->tb6_lock)); lockdep_is_held(&rt->fib6_table->tb6_lock));
enum fib_event_type event = FIB_EVENT_ENTRY_ADD;
struct fib6_info *iter = NULL, *match = NULL; struct fib6_info *iter = NULL, *match = NULL;
struct fib6_info __rcu **ins; struct fib6_info __rcu **ins;
int replace = (info->nlh && int replace = (info->nlh &&
...@@ -1013,6 +1014,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1013,6 +1014,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
"Can not append to a REJECT route"); "Can not append to a REJECT route");
return -EINVAL; return -EINVAL;
} }
event = FIB_EVENT_ENTRY_APPEND;
rt->fib6_nsiblings = match->fib6_nsiblings; rt->fib6_nsiblings = match->fib6_nsiblings;
list_add_tail(&rt->fib6_siblings, &match->fib6_siblings); list_add_tail(&rt->fib6_siblings, &match->fib6_siblings);
match->fib6_nsiblings++; match->fib6_nsiblings++;
...@@ -1034,15 +1036,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt, ...@@ -1034,15 +1036,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
* insert node * insert node
*/ */
if (!replace) { if (!replace) {
enum fib_event_type event;
if (!add) if (!add)
pr_warn("NLM_F_CREATE should be set when creating new route\n"); pr_warn("NLM_F_CREATE should be set when creating new route\n");
add: add:
nlflags |= NLM_F_CREATE; nlflags |= NLM_F_CREATE;
event = append ? FIB_EVENT_ENTRY_APPEND : FIB_EVENT_ENTRY_ADD;
err = call_fib6_entry_notifiers(info->nl_net, event, rt, err = call_fib6_entry_notifiers(info->nl_net, event, rt,
extack); extack);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment