mlxsw: spectrum_mr: Convert into using mr_mfc
authorYuval Mintz <yuvalm@mellanox.com>
Mon, 26 Mar 2018 12:01:41 +0000 (15:01 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 Mar 2018 17:14:44 +0000 (13:14 -0400)
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>
drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c

index a8f4927..ae8c5b5 100644 (file)
@@ -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)