Commit 4caef463 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller

mlxsw: spectrum_mr: Convert into using mr_mfc

Current multicast routing logic in driver assumes it's always meant to
deal with IPv4 multicast routes, leaving several placeholders for
later IPv6 support [currently usually WARN()].

This patch changes the driver's internal multicast route struct into
holding a common mr_mfc instead of the IPv4 mfc_cache.
The various placeholders are grouped into 2:
  - Functions that require only the common bits; These remain and the
    restriction for IPv4-only is lifted.
  - Function that require IPv4-specifics - for handling these functions
    we add sets of operations that encapsulate the protocol differences
Signed-off-by: default avatarYuval Mintz <yuvalm@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9742f866
...@@ -47,6 +47,11 @@ struct mlxsw_sp_mr { ...@@ -47,6 +47,11 @@ struct mlxsw_sp_mr {
/* priv has to be always the last item */ /* priv has to be always the last item */
}; };
struct mlxsw_sp_mr_vif;
struct mlxsw_sp_mr_vif_ops {
bool (*is_regular)(const struct mlxsw_sp_mr_vif *vif);
};
struct mlxsw_sp_mr_vif { struct mlxsw_sp_mr_vif {
struct net_device *dev; struct net_device *dev;
const struct mlxsw_sp_rif *rif; const struct mlxsw_sp_rif *rif;
...@@ -61,6 +66,9 @@ struct mlxsw_sp_mr_vif { ...@@ -61,6 +66,9 @@ struct mlxsw_sp_mr_vif {
* instance is used as an ingress VIF * instance is used as an ingress VIF
*/ */
struct list_head route_ivif_list; struct list_head route_ivif_list;
/* Protocol specific operations for a VIF */
const struct mlxsw_sp_mr_vif_ops *ops;
}; };
struct mlxsw_sp_mr_route_vif_entry { struct mlxsw_sp_mr_route_vif_entry {
...@@ -70,6 +78,17 @@ struct mlxsw_sp_mr_route_vif_entry { ...@@ -70,6 +78,17 @@ struct mlxsw_sp_mr_route_vif_entry {
struct mlxsw_sp_mr_route *mr_route; struct mlxsw_sp_mr_route *mr_route;
}; };
struct mlxsw_sp_mr_table;
struct mlxsw_sp_mr_table_ops {
bool (*is_route_valid)(const struct mlxsw_sp_mr_table *mr_table,
const struct mr_mfc *mfc);
void (*key_create)(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route_key *key,
struct mr_mfc *mfc);
bool (*is_route_starg)(const struct mlxsw_sp_mr_table *mr_table,
const struct mlxsw_sp_mr_route *mr_route);
};
struct mlxsw_sp_mr_table { struct mlxsw_sp_mr_table {
struct list_head node; struct list_head node;
enum mlxsw_sp_l3proto proto; enum mlxsw_sp_l3proto proto;
...@@ -78,6 +97,7 @@ struct mlxsw_sp_mr_table { ...@@ -78,6 +97,7 @@ struct mlxsw_sp_mr_table {
struct mlxsw_sp_mr_vif vifs[MAXVIFS]; struct mlxsw_sp_mr_vif vifs[MAXVIFS];
struct list_head route_list; struct list_head route_list;
struct rhashtable route_ht; struct rhashtable route_ht;
const struct mlxsw_sp_mr_table_ops *ops;
char catchall_route_priv[0]; char catchall_route_priv[0];
/* catchall_route_priv has to be always the last item */ /* catchall_route_priv has to be always the last item */
}; };
...@@ -88,7 +108,7 @@ struct mlxsw_sp_mr_route { ...@@ -88,7 +108,7 @@ struct mlxsw_sp_mr_route {
struct mlxsw_sp_mr_route_key key; struct mlxsw_sp_mr_route_key key;
enum mlxsw_sp_mr_route_action route_action; enum mlxsw_sp_mr_route_action route_action;
u16 min_mtu; u16 min_mtu;
struct mfc_cache *mfc4; struct mr_mfc *mfc;
void *route_priv; void *route_priv;
const struct mlxsw_sp_mr_table *mr_table; const struct mlxsw_sp_mr_table *mr_table;
/* A list of route_vif_entry structs that point to the egress VIFs */ /* A list of route_vif_entry structs that point to the egress VIFs */
...@@ -104,14 +124,9 @@ static const struct rhashtable_params mlxsw_sp_mr_route_ht_params = { ...@@ -104,14 +124,9 @@ static const struct rhashtable_params mlxsw_sp_mr_route_ht_params = {
.automatic_shrinking = true, .automatic_shrinking = true,
}; };
static bool mlxsw_sp_mr_vif_regular(const struct mlxsw_sp_mr_vif *vif)
{
return !(vif->vif_flags & (VIFF_TUNNEL | VIFF_REGISTER));
}
static bool mlxsw_sp_mr_vif_valid(const struct mlxsw_sp_mr_vif *vif) static bool mlxsw_sp_mr_vif_valid(const struct mlxsw_sp_mr_vif *vif)
{ {
return mlxsw_sp_mr_vif_regular(vif) && vif->dev && vif->rif; return vif->ops->is_regular(vif) && vif->dev && vif->rif;
} }
static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif) static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif)
...@@ -122,18 +137,9 @@ static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif) ...@@ -122,18 +137,9 @@ static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif)
static bool static bool
mlxsw_sp_mr_route_ivif_in_evifs(const struct mlxsw_sp_mr_route *mr_route) mlxsw_sp_mr_route_ivif_in_evifs(const struct mlxsw_sp_mr_route *mr_route)
{ {
vifi_t ivif; vifi_t ivif = mr_route->mfc->mfc_parent;
switch (mr_route->mr_table->proto) { return mr_route->mfc->mfc_un.res.ttls[ivif] != 255;
case MLXSW_SP_L3_PROTO_IPV4:
ivif = mr_route->mfc4->_c.mfc_parent;
return mr_route->mfc4->_c.mfc_un.res.ttls[ivif] != 255;
case MLXSW_SP_L3_PROTO_IPV6:
/* fall through */
default:
WARN_ON_ONCE(1);
}
return false;
} }
static int static int
...@@ -149,19 +155,6 @@ mlxsw_sp_mr_route_valid_evifs_num(const struct mlxsw_sp_mr_route *mr_route) ...@@ -149,19 +155,6 @@ mlxsw_sp_mr_route_valid_evifs_num(const struct mlxsw_sp_mr_route *mr_route)
return valid_evifs; return valid_evifs;
} }
static bool mlxsw_sp_mr_route_starg(const struct mlxsw_sp_mr_route *mr_route)
{
switch (mr_route->mr_table->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
return mr_route->key.source_mask.addr4 == htonl(INADDR_ANY);
case MLXSW_SP_L3_PROTO_IPV6:
/* fall through */
default:
WARN_ON_ONCE(1);
}
return false;
}
static enum mlxsw_sp_mr_route_action static enum mlxsw_sp_mr_route_action
mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route) mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route)
{ {
...@@ -174,7 +167,8 @@ mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route) ...@@ -174,7 +167,8 @@ mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route)
/* The kernel does not match a (*,G) route that the ingress interface is /* The kernel does not match a (*,G) route that the ingress interface is
* not one of the egress interfaces, so trap these kind of routes. * not one of the egress interfaces, so trap these kind of routes.
*/ */
if (mlxsw_sp_mr_route_starg(mr_route) && if (mr_route->mr_table->ops->is_route_starg(mr_route->mr_table,
mr_route) &&
!mlxsw_sp_mr_route_ivif_in_evifs(mr_route)) !mlxsw_sp_mr_route_ivif_in_evifs(mr_route))
return MLXSW_SP_MR_ROUTE_ACTION_TRAP; return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
...@@ -195,25 +189,11 @@ mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route) ...@@ -195,25 +189,11 @@ mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route)
static enum mlxsw_sp_mr_route_prio static enum mlxsw_sp_mr_route_prio
mlxsw_sp_mr_route_prio(const struct mlxsw_sp_mr_route *mr_route) mlxsw_sp_mr_route_prio(const struct mlxsw_sp_mr_route *mr_route)
{ {
return mlxsw_sp_mr_route_starg(mr_route) ? return mr_route->mr_table->ops->is_route_starg(mr_route->mr_table,
mr_route) ?
MLXSW_SP_MR_ROUTE_PRIO_STARG : MLXSW_SP_MR_ROUTE_PRIO_SG; MLXSW_SP_MR_ROUTE_PRIO_STARG : MLXSW_SP_MR_ROUTE_PRIO_SG;
} }
static void mlxsw_sp_mr_route4_key(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route_key *key,
const struct mfc_cache *mfc)
{
bool starg = (mfc->mfc_origin == htonl(INADDR_ANY));
memset(key, 0, sizeof(*key));
key->vrid = mr_table->vr_id;
key->proto = mr_table->proto;
key->group.addr4 = mfc->mfc_mcastgrp;
key->group_mask.addr4 = htonl(0xffffffff);
key->source.addr4 = mfc->mfc_origin;
key->source_mask.addr4 = htonl(starg ? 0 : 0xffffffff);
}
static int mlxsw_sp_mr_route_evif_link(struct mlxsw_sp_mr_route *mr_route, static int mlxsw_sp_mr_route_evif_link(struct mlxsw_sp_mr_route *mr_route,
struct mlxsw_sp_mr_vif *mr_vif) struct mlxsw_sp_mr_vif *mr_vif)
{ {
...@@ -356,12 +336,13 @@ mlxsw_sp_mr_route4_create(struct mlxsw_sp_mr_table *mr_table, ...@@ -356,12 +336,13 @@ mlxsw_sp_mr_route4_create(struct mlxsw_sp_mr_table *mr_table,
if (!mr_route) if (!mr_route)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&mr_route->evif_list); INIT_LIST_HEAD(&mr_route->evif_list);
mlxsw_sp_mr_route4_key(mr_table, &mr_route->key, mfc);
/* Find min_mtu and link iVIF and eVIFs */ /* Find min_mtu and link iVIF and eVIFs */
mr_route->min_mtu = ETH_MAX_MTU; mr_route->min_mtu = ETH_MAX_MTU;
mr_cache_hold(&mfc->_c); mr_cache_hold(&mfc->_c);
mr_route->mfc4 = mfc; mr_route->mfc = &mfc->_c;
mr_table->ops->key_create(mr_table, &mr_route->key, mr_route->mfc);
mr_route->mr_table = mr_table; mr_route->mr_table = mr_table;
for (i = 0; i < MAXVIFS; i++) { for (i = 0; i < MAXVIFS; i++) {
if (mfc->_c.mfc_un.res.ttls[i] != 255) { if (mfc->_c.mfc_un.res.ttls[i] != 255) {
...@@ -393,7 +374,7 @@ static void mlxsw_sp_mr_route4_destroy(struct mlxsw_sp_mr_table *mr_table, ...@@ -393,7 +374,7 @@ static void mlxsw_sp_mr_route4_destroy(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route_vif_entry *rve, *tmp; struct mlxsw_sp_mr_route_vif_entry *rve, *tmp;
mlxsw_sp_mr_route_ivif_unlink(mr_route); mlxsw_sp_mr_route_ivif_unlink(mr_route);
mr_cache_put((struct mr_mfc *)mr_route->mfc4); mr_cache_put((struct mr_mfc *)mr_route->mfc);
list_for_each_entry_safe(rve, tmp, &mr_route->evif_list, route_node) list_for_each_entry_safe(rve, tmp, &mr_route->evif_list, route_node)
mlxsw_sp_mr_route_evif_unlink(rve); mlxsw_sp_mr_route_evif_unlink(rve);
kfree(mr_route); kfree(mr_route);
...@@ -416,18 +397,10 @@ static void mlxsw_sp_mr_route_destroy(struct mlxsw_sp_mr_table *mr_table, ...@@ -416,18 +397,10 @@ static void mlxsw_sp_mr_route_destroy(struct mlxsw_sp_mr_table *mr_table,
static void mlxsw_sp_mr_mfc_offload_set(struct mlxsw_sp_mr_route *mr_route, static void mlxsw_sp_mr_mfc_offload_set(struct mlxsw_sp_mr_route *mr_route,
bool offload) bool offload)
{ {
switch (mr_route->mr_table->proto) { if (offload)
case MLXSW_SP_L3_PROTO_IPV4: mr_route->mfc->mfc_flags |= MFC_OFFLOAD;
if (offload) else
mr_route->mfc4->_c.mfc_flags |= MFC_OFFLOAD; mr_route->mfc->mfc_flags &= ~MFC_OFFLOAD;
else
mr_route->mfc4->_c.mfc_flags &= ~MFC_OFFLOAD;
break;
case MLXSW_SP_L3_PROTO_IPV6:
/* fall through */
default:
WARN_ON_ONCE(1);
}
} }
static void mlxsw_sp_mr_mfc_offload_update(struct mlxsw_sp_mr_route *mr_route) static void mlxsw_sp_mr_mfc_offload_update(struct mlxsw_sp_mr_route *mr_route)
...@@ -456,15 +429,8 @@ int mlxsw_sp_mr_route4_add(struct mlxsw_sp_mr_table *mr_table, ...@@ -456,15 +429,8 @@ int mlxsw_sp_mr_route4_add(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route *mr_route; struct mlxsw_sp_mr_route *mr_route;
int err; int err;
/* If the route is a (*,*) route, abort, as these kind of routes are if (!mr_table->ops->is_route_valid(mr_table, &mfc->_c))
* used for proxy routes.
*/
if (mfc->mfc_origin == htonl(INADDR_ANY) &&
mfc->mfc_mcastgrp == htonl(INADDR_ANY)) {
dev_warn(mr_table->mlxsw_sp->bus_info->dev,
"Offloading proxy routes is not supported.\n");
return -EINVAL; return -EINVAL;
}
/* Create a new route */ /* Create a new route */
mr_route = mlxsw_sp_mr_route4_create(mr_table, mfc); mr_route = mlxsw_sp_mr_route4_create(mr_table, mfc);
...@@ -535,7 +501,7 @@ void mlxsw_sp_mr_route4_del(struct mlxsw_sp_mr_table *mr_table, ...@@ -535,7 +501,7 @@ void mlxsw_sp_mr_route4_del(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route *mr_route; struct mlxsw_sp_mr_route *mr_route;
struct mlxsw_sp_mr_route_key key; struct mlxsw_sp_mr_route_key key;
mlxsw_sp_mr_route4_key(mr_table, &key, mfc); mr_table->ops->key_create(mr_table, &key, &mfc->_c);
mr_route = rhashtable_lookup_fast(&mr_table->route_ht, &key, mr_route = rhashtable_lookup_fast(&mr_table->route_ht, &key,
mlxsw_sp_mr_route_ht_params); mlxsw_sp_mr_route_ht_params);
if (mr_route) if (mr_route)
...@@ -840,6 +806,70 @@ void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table, ...@@ -840,6 +806,70 @@ void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table,
} }
} }
/* Protocol specific functions */
static bool
mlxsw_sp_mr_route4_validate(const struct mlxsw_sp_mr_table *mr_table,
const struct mr_mfc *c)
{
struct mfc_cache *mfc = (struct mfc_cache *) c;
/* If the route is a (*,*) route, abort, as these kind of routes are
* used for proxy routes.
*/
if (mfc->mfc_origin == htonl(INADDR_ANY) &&
mfc->mfc_mcastgrp == htonl(INADDR_ANY)) {
dev_warn(mr_table->mlxsw_sp->bus_info->dev,
"Offloading proxy routes is not supported.\n");
return false;
}
return true;
}
static void mlxsw_sp_mr_route4_key(struct mlxsw_sp_mr_table *mr_table,
struct mlxsw_sp_mr_route_key *key,
struct mr_mfc *c)
{
const struct mfc_cache *mfc = (struct mfc_cache *) c;
bool starg;
starg = (mfc->mfc_origin == htonl(INADDR_ANY));
memset(key, 0, sizeof(*key));
key->vrid = mr_table->vr_id;
key->proto = MLXSW_SP_L3_PROTO_IPV4;
key->group.addr4 = mfc->mfc_mcastgrp;
key->group_mask.addr4 = htonl(0xffffffff);
key->source.addr4 = mfc->mfc_origin;
key->source_mask.addr4 = htonl(starg ? 0 : 0xffffffff);
}
static bool mlxsw_sp_mr_route4_starg(const struct mlxsw_sp_mr_table *mr_table,
const struct mlxsw_sp_mr_route *mr_route)
{
return mr_route->key.source_mask.addr4 == htonl(INADDR_ANY);
}
static bool mlxsw_sp_mr_vif4_is_regular(const struct mlxsw_sp_mr_vif *vif)
{
return !(vif->vif_flags & (VIFF_TUNNEL | VIFF_REGISTER));
}
static struct
mlxsw_sp_mr_vif_ops mlxsw_sp_mr_vif_ops_arr[] = {
{
.is_regular = mlxsw_sp_mr_vif4_is_regular,
},
};
static struct
mlxsw_sp_mr_table_ops mlxsw_sp_mr_table_ops_arr[] = {
{
.is_route_valid = mlxsw_sp_mr_route4_validate,
.key_create = mlxsw_sp_mr_route4_key,
.is_route_starg = mlxsw_sp_mr_route4_starg,
},
};
struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp,
u32 vr_id, u32 vr_id,
enum mlxsw_sp_l3proto proto) enum mlxsw_sp_l3proto proto)
...@@ -867,6 +897,7 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp, ...@@ -867,6 +897,7 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp,
mr_table->vr_id = vr_id; mr_table->vr_id = vr_id;
mr_table->mlxsw_sp = mlxsw_sp; mr_table->mlxsw_sp = mlxsw_sp;
mr_table->proto = proto; mr_table->proto = proto;
mr_table->ops = &mlxsw_sp_mr_table_ops_arr[proto];
INIT_LIST_HEAD(&mr_table->route_list); INIT_LIST_HEAD(&mr_table->route_list);
err = rhashtable_init(&mr_table->route_ht, err = rhashtable_init(&mr_table->route_ht,
...@@ -877,6 +908,7 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp, ...@@ -877,6 +908,7 @@ struct mlxsw_sp_mr_table *mlxsw_sp_mr_table_create(struct mlxsw_sp *mlxsw_sp,
for (i = 0; i < MAXVIFS; i++) { for (i = 0; i < MAXVIFS; i++) {
INIT_LIST_HEAD(&mr_table->vifs[i].route_evif_list); INIT_LIST_HEAD(&mr_table->vifs[i].route_evif_list);
INIT_LIST_HEAD(&mr_table->vifs[i].route_ivif_list); INIT_LIST_HEAD(&mr_table->vifs[i].route_ivif_list);
mr_table->vifs[i].ops = &mlxsw_sp_mr_vif_ops_arr[proto];
} }
err = mr->mr_ops->route_create(mlxsw_sp, mr->priv, err = mr->mr_ops->route_create(mlxsw_sp, mr->priv,
...@@ -943,18 +975,10 @@ static void mlxsw_sp_mr_route_stats_update(struct mlxsw_sp *mlxsw_sp, ...@@ -943,18 +975,10 @@ static void mlxsw_sp_mr_route_stats_update(struct mlxsw_sp *mlxsw_sp,
mr->mr_ops->route_stats(mlxsw_sp, mr_route->route_priv, &packets, mr->mr_ops->route_stats(mlxsw_sp, mr_route->route_priv, &packets,
&bytes); &bytes);
switch (mr_route->mr_table->proto) { if (mr_route->mfc->mfc_un.res.pkt != packets)
case MLXSW_SP_L3_PROTO_IPV4: mr_route->mfc->mfc_un.res.lastuse = jiffies;
if (mr_route->mfc4->_c.mfc_un.res.pkt != packets) mr_route->mfc->mfc_un.res.pkt = packets;
mr_route->mfc4->_c.mfc_un.res.lastuse = jiffies; mr_route->mfc->mfc_un.res.bytes = bytes;
mr_route->mfc4->_c.mfc_un.res.pkt = packets;
mr_route->mfc4->_c.mfc_un.res.bytes = bytes;
break;
case MLXSW_SP_L3_PROTO_IPV6:
/* fall through */
default:
WARN_ON_ONCE(1);
}
} }
static void mlxsw_sp_mr_stats_update(struct work_struct *work) static void mlxsw_sp_mr_stats_update(struct work_struct *work)
......
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