]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mlxsw: Configure ingress RIF classification
authorAmit Cohen <amcohen@nvidia.com>
Mon, 4 Jul 2022 06:11:29 +0000 (09:11 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 4 Jul 2022 08:56:57 +0000 (09:56 +0100)
Before layer 2 forwarding, the device classifies an incoming packet to
a FID. The classification is done based on one of the following keys:

1. FID
2. VNI (after decapsulation)
3. VID / {Port, VID}

After classification, the FID is known, but also all the attributes of
the FID, such as the router interface (RIF) via which a packet that
needs to be routed will ingress the router block.

In the legacy model, when a RIF was created / destroyed, it was
firmware's responsibility to update it in the previously mentioned FID
classification records. In the unified bridge model, this responsibility
moved to software.

The third classification requires to iterate over the FID's {Port, VID}
list and issue SVFA write with the correct mapping table according to the
port's mode (virtual or not). We never map multiple VLANs to the same FID
using VID->FID mapping, so such a mapping needs to be performed once.

When a new FID classification entry is configured and the FID already has
a RIF, set the RIF as part of SVFA configuration.

The reverse needs to be done when clearing a RIF from a FID. Currently,
clearing is done by issuing mlxsw_sp_fid_rif_set() with a NULL RIF pointer.
Instead, introduce mlxsw_sp_fid_rif_unset().

Note that mlxsw_sp_fid_rif_set() is called after the RIF is fully
operational, so it conforms to the internal requirement regarding
SVFA.irif_v: "Must not be set for a non-enabled RIF".

Do not set the ingress RIF for rFIDs, as the {Port, VID}->rFID entry is
configured by firmware when legacy model is used, a next patch will
handle this configuration for rFIDs and unified bridge model.

Signed-off-by: Amit Cohen <amcohen@nvidia.com>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h

index b0b5806a22ed628aaa30f4bb4cd8a6f5345f9c9b..46ed2c1810becd4f9631c457ea7d77e2ec819792 100644 (file)
@@ -1658,40 +1658,43 @@ MLXSW_ITEM32(reg, svfa, irif, 0x14, 0, 16);
 
 static inline void __mlxsw_reg_svfa_pack(char *payload,
                                         enum mlxsw_reg_svfa_mt mt, bool valid,
-                                        u16 fid)
+                                        u16 fid, bool irif_v, u16 irif)
 {
        MLXSW_REG_ZERO(svfa, payload);
        mlxsw_reg_svfa_swid_set(payload, 0);
        mlxsw_reg_svfa_mapping_table_set(payload, mt);
        mlxsw_reg_svfa_v_set(payload, valid);
        mlxsw_reg_svfa_fid_set(payload, fid);
+       mlxsw_reg_svfa_irif_v_set(payload, irif_v);
+       mlxsw_reg_svfa_irif_set(payload, irif_v ? irif : 0);
 }
 
 static inline void mlxsw_reg_svfa_port_vid_pack(char *payload, u16 local_port,
-                                               bool valid, u16 fid, u16 vid)
+                                               bool valid, u16 fid, u16 vid,
+                                               bool irif_v, u16 irif)
 {
        enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
 
-       __mlxsw_reg_svfa_pack(payload, mt, valid, fid);
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
        mlxsw_reg_svfa_local_port_set(payload, local_port);
        mlxsw_reg_svfa_vid_set(payload, vid);
 }
 
 static inline void mlxsw_reg_svfa_vid_pack(char *payload, bool valid, u16 fid,
-                                          u16 vid)
+                                          u16 vid, bool irif_v, u16 irif)
 {
        enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
 
-       __mlxsw_reg_svfa_pack(payload, mt, valid, fid);
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
        mlxsw_reg_svfa_vid_set(payload, vid);
 }
 
 static inline void mlxsw_reg_svfa_vni_pack(char *payload, bool valid, u16 fid,
-                                          u32 vni)
+                                          u32 vni, bool irif_v, u16 irif)
 {
        enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VNI_TO_FID;
 
-       __mlxsw_reg_svfa_pack(payload, mt, valid, fid);
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
        mlxsw_reg_svfa_vni_set(payload, vni);
 }
 
index 8de3bdcdf143436e516eef5714fca3e008179e82..b1810a22a1a61eb7c1b922cac09afdaa3300cfe3 100644 (file)
@@ -737,6 +737,7 @@ union mlxsw_sp_l3addr {
        struct in6_addr addr6;
 };
 
+u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
 int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
                         struct netlink_ext_ack *extack);
 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
@@ -1285,7 +1286,8 @@ void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
                                 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
-void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid);
 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid);
 enum mlxsw_sp_rif_type
 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
index ffe8c583865d486529096f7dcb16ad106003f475..a8fecf47eaf534de057d52989b91522d73d4c3b5 100644 (file)
@@ -404,11 +404,6 @@ enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
        return fid->fid_family->type;
 }
 
-void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
-{
-       fid->rif = rif;
-}
-
 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
 {
        return fid->rif;
@@ -465,7 +460,8 @@ static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
-static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid)
+static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
+                               const struct mlxsw_sp_rif *rif)
 {
        struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        enum mlxsw_reg_bridge_type bridge_type = 0;
@@ -484,32 +480,176 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid)
        mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
        mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
        mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
+
+       if (mlxsw_sp->ubridge && rif) {
+               mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
+               mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
+       }
+
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
 static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
+                                      const struct mlxsw_sp_rif *rif,
                                       bool valid)
 {
        struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        char svfa_pl[MLXSW_REG_SVFA_LEN];
+       bool irif_valid;
+       u16 irif_index;
+
+       irif_valid = !!rif;
+       irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
 
        mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
-                               be32_to_cpu(fid->vni));
+                               be32_to_cpu(fid->vni), irif_valid, irif_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                         const struct mlxsw_sp_rif *rif)
+{
+       return mlxsw_sp_fid_edit_op(fid, rif);
+}
+
+static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                             const struct mlxsw_sp_rif *rif)
+{
+       if (!fid->vni_valid)
+               return 0;
+
+       return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
+}
+
+static int
+mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
+                                           struct mlxsw_sp_fid_port_vid *pv,
+                                           bool irif_valid, u16 irif_index)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       char svfa_pl[MLXSW_REG_SVFA_LEN];
+
+       mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
+                                    fid->fid_index, pv->vid, irif_valid,
+                                    irif_index);
+
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
 }
 
+static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
+                                          const struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       struct mlxsw_sp_fid_port_vid *pv;
+       u16 irif_index;
+       int err;
+
+       irif_index = mlxsw_sp_rif_index(rif);
+
+       list_for_each_entry(pv, &fid->port_vid_list, list) {
+               /* If port is not in virtual mode, then it does not have any
+                * {Port, VID}->FID mappings that need to be updated with the
+                * ingress RIF.
+                */
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
+                                                                 true,
+                                                                 irif_index);
+               if (err)
+                       goto err_port_vid_to_fid_rif_update_one;
+       }
+
+       return 0;
+
+err_port_vid_to_fid_rif_update_one:
+       list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
+       }
+
+       return err;
+}
+
+static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       struct mlxsw_sp_fid_port_vid *pv;
+
+       list_for_each_entry(pv, &fid->port_vid_list, list) {
+               /* If port is not in virtual mode, then it does not have any
+                * {Port, VID}->FID mappings that need to be updated.
+                */
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
+       }
+}
+
+int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
+{
+       int err;
+
+       if (!fid->fid_family->mlxsw_sp->ubridge) {
+               fid->rif = rif;
+               return 0;
+       }
+
+       err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
+       if (err)
+               goto err_vni_to_fid_rif_update;
+
+       err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
+       if (err)
+               goto err_vid_to_fid_rif_set;
+
+       fid->rif = rif;
+       return 0;
+
+err_vid_to_fid_rif_set:
+       mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
+err_vni_to_fid_rif_update:
+       mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
+       return err;
+}
+
+void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
+{
+       if (!fid->fid_family->mlxsw_sp->ubridge) {
+               fid->rif = NULL;
+               return;
+       }
+
+       if (!fid->rif)
+               return;
+
+       fid->rif = NULL;
+       mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
+       mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
+       mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
+}
+
 static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
 {
        struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        int err;
 
        if (mlxsw_sp->ubridge) {
-               err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->vni_valid);
+               err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif,
+                                                 fid->vni_valid);
                if (err)
                        return err;
        }
 
-       err = mlxsw_sp_fid_edit_op(fid);
+       err = mlxsw_sp_fid_edit_op(fid, fid->rif);
        if (err)
                goto err_fid_edit_op;
 
@@ -517,7 +657,7 @@ static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
 
 err_fid_edit_op:
        if (mlxsw_sp->ubridge)
-               mlxsw_sp_fid_vni_to_fid_map(fid, !fid->vni_valid);
+               mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
        return err;
 }
 
@@ -526,9 +666,16 @@ static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
 {
        struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        char svfa_pl[MLXSW_REG_SVFA_LEN];
+       bool irif_valid = false;
+       u16 irif_index = 0;
+
+       if (mlxsw_sp->ubridge && fid->rif) {
+               irif_valid = true;
+               irif_index = mlxsw_sp_rif_index(fid->rif);
+       }
 
        mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
-                                    vid);
+                                    vid, irif_valid, irif_index);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
 }
 
@@ -768,12 +915,12 @@ static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
 
 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
 {
-       return mlxsw_sp_fid_edit_op(fid);
+       return mlxsw_sp_fid_edit_op(fid, fid->rif);
 }
 
 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
 {
-       mlxsw_sp_fid_edit_op(fid);
+       mlxsw_sp_fid_edit_op(fid, fid->rif);
 }
 
 static void
index 63652460c40d1c2170331b051eab7d751168e149..4a34138985bf67284a3954067e420deb0fab52c7 100644 (file)
@@ -9351,9 +9351,15 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
        if (err)
                goto err_rif_fdb_op;
 
-       mlxsw_sp_fid_rif_set(rif->fid, rif);
+       err = mlxsw_sp_fid_rif_set(rif->fid, rif);
+       if (err)
+               goto err_fid_rif_set;
+
        return 0;
 
+err_fid_rif_set:
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
 err_rif_fdb_op:
        mlxsw_sp_rif_subport_op(rif, false);
 err_rif_subport_op:
@@ -9365,7 +9371,7 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
 {
        struct mlxsw_sp_fid *fid = rif->fid;
 
-       mlxsw_sp_fid_rif_set(fid, NULL);
+       mlxsw_sp_fid_rif_unset(fid);
        mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
                            mlxsw_sp_fid_index(fid), false);
        mlxsw_sp_rif_macvlan_flush(rif);
@@ -9442,9 +9448,15 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
        if (err)
                goto err_rif_fdb_op;
 
-       mlxsw_sp_fid_rif_set(rif->fid, rif);
+       err = mlxsw_sp_fid_rif_set(rif->fid, rif);
+       if (err)
+               goto err_fid_rif_set;
+
        return 0;
 
+err_fid_rif_set:
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
 err_rif_fdb_op:
        mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
                               mlxsw_sp_router_port(mlxsw_sp), false);
@@ -9464,7 +9476,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        struct mlxsw_sp_fid *fid = rif->fid;
 
-       mlxsw_sp_fid_rif_set(fid, NULL);
+       mlxsw_sp_fid_rif_unset(fid);
        mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
                            mlxsw_sp_fid_index(fid), false);
        mlxsw_sp_rif_macvlan_flush(rif);
index b5c83ec7a87f913e70cfd6191905f034aef18763..c5dfb972b433dd27f6043945cc2e1ac88f083fe4 100644 (file)
@@ -82,7 +82,6 @@ struct mlxsw_sp_ipip_entry;
 
 struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
                                           u16 rif_index);
-u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
 u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *rif);
 u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *rif);
 u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif);