mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-01 16:57:18 +09:00
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: Yuval Mintz <yuvalm@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
9742f866bd
commit
4caef4638f
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user