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 {
/* 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 net_device *dev;
const struct mlxsw_sp_rif *rif;
......@@ -61,6 +66,9 @@ struct mlxsw_sp_mr_vif {
* instance is used as an ingress VIF
*/
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 {
......@@ -70,6 +78,17 @@ struct mlxsw_sp_mr_route_vif_entry {
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 list_head node;
enum mlxsw_sp_l3proto proto;
......@@ -78,6 +97,7 @@ struct mlxsw_sp_mr_table {
struct mlxsw_sp_mr_vif vifs[MAXVIFS];
struct list_head route_list;
struct rhashtable route_ht;
const struct mlxsw_sp_mr_table_ops *ops;
char catchall_route_priv[0];
/* catchall_route_priv has to be always the last item */
};
......@@ -88,7 +108,7 @@ struct mlxsw_sp_mr_route {
struct mlxsw_sp_mr_route_key key;
enum mlxsw_sp_mr_route_action route_action;
u16 min_mtu;
struct mfc_cache *mfc4;
struct mr_mfc *mfc;
void *route_priv;
const struct mlxsw_sp_mr_table *mr_table;
/* 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 = {
.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)
{
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)
......@@ -122,18 +137,9 @@ static bool mlxsw_sp_mr_vif_exists(const struct mlxsw_sp_mr_vif *vif)
static bool
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) {
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;
return mr_route->mfc->mfc_un.res.ttls[ivif] != 255;
}
static int
......@@ -149,19 +155,6 @@ mlxsw_sp_mr_route_valid_evifs_num(const struct mlxsw_sp_mr_route *mr_route)
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
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
* 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))
return MLXSW_SP_MR_ROUTE_ACTION_TRAP;
......@@ -195,25 +189,11 @@ mlxsw_sp_mr_route_action(const struct mlxsw_sp_mr_route *mr_route)
static enum mlxsw_sp_mr_route_prio
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;
}
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,
struct mlxsw_sp_mr_vif *mr_vif)
{
......@@ -356,12 +336,13 @@ mlxsw_sp_mr_route4_create(struct mlxsw_sp_mr_table *mr_table,
if (!mr_route)
return ERR_PTR(-ENOMEM);
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 */
mr_route->min_mtu = ETH_MAX_MTU;
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;
for (i = 0; i < MAXVIFS; i++) {
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,
struct mlxsw_sp_mr_route_vif_entry *rve, *tmp;
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)
mlxsw_sp_mr_route_evif_unlink(rve);
kfree(mr_route);
......@@ -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,
bool offload)
{
switch (mr_route->mr_table->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
if (offload)
mr_route->mfc4->_c.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);
}
if (offload)
mr_route->mfc->mfc_flags |= MFC_OFFLOAD;
else
mr_route->mfc->mfc_flags &= ~MFC_OFFLOAD;
}
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,
struct mlxsw_sp_mr_route *mr_route;
int err;
/* 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");
if (!mr_table->ops->is_route_valid(mr_table, &mfc->_c))
return -EINVAL;
}
/* Create a new route */
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,
struct mlxsw_sp_mr_route *mr_route;
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,
mlxsw_sp_mr_route_ht_params);
if (mr_route)
......@@ -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,
u32 vr_id,
enum mlxsw_sp_l3proto proto)
......@@ -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->mlxsw_sp = mlxsw_sp;
mr_table->proto = proto;
mr_table->ops = &mlxsw_sp_mr_table_ops_arr[proto];
INIT_LIST_HEAD(&mr_table->route_list);
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,
for (i = 0; i < MAXVIFS; i++) {
INIT_LIST_HEAD(&mr_table->vifs[i].route_evif_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,
......@@ -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,
&bytes);
switch (mr_route->mr_table->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
if (mr_route->mfc4->_c.mfc_un.res.pkt != packets)
mr_route->mfc4->_c.mfc_un.res.lastuse = jiffies;
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);
}
if (mr_route->mfc->mfc_un.res.pkt != packets)
mr_route->mfc->mfc_un.res.lastuse = jiffies;
mr_route->mfc->mfc_un.res.pkt = packets;
mr_route->mfc->mfc_un.res.bytes = bytes;
}
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