Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/kernel.h>
0005 
0006 #include "core_acl_flex_actions.h"
0007 #include "spectrum.h"
0008 #include "spectrum_mr.h"
0009 
0010 struct mlxsw_sp2_mr_tcam {
0011     struct mlxsw_sp *mlxsw_sp;
0012     struct mlxsw_sp_flow_block *flow_block;
0013     struct mlxsw_sp_acl_ruleset *ruleset4;
0014     struct mlxsw_sp_acl_ruleset *ruleset6;
0015 };
0016 
0017 struct mlxsw_sp2_mr_route {
0018     struct mlxsw_sp2_mr_tcam *mr_tcam;
0019 };
0020 
0021 static struct mlxsw_sp_acl_ruleset *
0022 mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
0023                 enum mlxsw_sp_l3proto proto)
0024 {
0025     switch (proto) {
0026     case MLXSW_SP_L3_PROTO_IPV4:
0027         return mr_tcam->ruleset4;
0028     case MLXSW_SP_L3_PROTO_IPV6:
0029         return mr_tcam->ruleset6;
0030     }
0031     return NULL;
0032 }
0033 
0034 static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
0035                     enum mlxsw_reg_pemrbt_protocol protocol,
0036                     struct mlxsw_sp_acl_ruleset *ruleset)
0037 {
0038     char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
0039     u16 group_id;
0040 
0041     group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
0042 
0043     mlxsw_reg_pemrbt_pack(pemrbt_pl, protocol, group_id);
0044     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
0045 }
0046 
0047 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
0048         MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0049         MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0050         MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0051         MLXSW_AFK_ELEMENT_DST_IP_0_31,
0052 };
0053 
0054 static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
0055 {
0056     struct mlxsw_afk_element_usage elusage;
0057     int err;
0058 
0059     /* Initialize IPv4 ACL group. */
0060     mlxsw_afk_element_usage_fill(&elusage,
0061                      mlxsw_sp2_mr_tcam_usage_ipv4,
0062                      ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
0063     mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
0064                              mr_tcam->flow_block,
0065                              MLXSW_SP_L3_PROTO_IPV4,
0066                              MLXSW_SP_ACL_PROFILE_MR,
0067                              &elusage);
0068 
0069     if (IS_ERR(mr_tcam->ruleset4))
0070         return PTR_ERR(mr_tcam->ruleset4);
0071 
0072     /* MC Router groups should be bound before routes are inserted. */
0073     err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
0074                        MLXSW_REG_PEMRBT_PROTO_IPV4,
0075                        mr_tcam->ruleset4);
0076     if (err)
0077         goto err_bind_group;
0078 
0079     return 0;
0080 
0081 err_bind_group:
0082     mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
0083     return err;
0084 }
0085 
0086 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
0087 {
0088     mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
0089 }
0090 
0091 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
0092         MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0093         MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0094         MLXSW_AFK_ELEMENT_SRC_IP_96_127,
0095         MLXSW_AFK_ELEMENT_SRC_IP_64_95,
0096         MLXSW_AFK_ELEMENT_SRC_IP_32_63,
0097         MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0098         MLXSW_AFK_ELEMENT_DST_IP_96_127,
0099         MLXSW_AFK_ELEMENT_DST_IP_64_95,
0100         MLXSW_AFK_ELEMENT_DST_IP_32_63,
0101         MLXSW_AFK_ELEMENT_DST_IP_0_31,
0102 };
0103 
0104 static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
0105 {
0106     struct mlxsw_afk_element_usage elusage;
0107     int err;
0108 
0109     /* Initialize IPv6 ACL group */
0110     mlxsw_afk_element_usage_fill(&elusage,
0111                      mlxsw_sp2_mr_tcam_usage_ipv6,
0112                      ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
0113     mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
0114                              mr_tcam->flow_block,
0115                              MLXSW_SP_L3_PROTO_IPV6,
0116                              MLXSW_SP_ACL_PROFILE_MR,
0117                              &elusage);
0118 
0119     if (IS_ERR(mr_tcam->ruleset6))
0120         return PTR_ERR(mr_tcam->ruleset6);
0121 
0122     /* MC Router groups should be bound before routes are inserted. */
0123     err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
0124                        MLXSW_REG_PEMRBT_PROTO_IPV6,
0125                        mr_tcam->ruleset6);
0126     if (err)
0127         goto err_bind_group;
0128 
0129     return 0;
0130 
0131 err_bind_group:
0132     mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
0133     return err;
0134 }
0135 
0136 static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
0137 {
0138     mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
0139 }
0140 
0141 static void
0142 mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
0143                   struct mlxsw_sp_mr_route_key *key)
0144 {
0145     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0146                        (char *) &key->source.addr4,
0147                        (char *) &key->source_mask.addr4, 4);
0148     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
0149                        (char *) &key->group.addr4,
0150                        (char *) &key->group_mask.addr4, 4);
0151 }
0152 
0153 static void
0154 mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
0155                   struct mlxsw_sp_mr_route_key *key)
0156 {
0157     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
0158                        &key->source.addr6.s6_addr[0x0],
0159                        &key->source_mask.addr6.s6_addr[0x0], 4);
0160     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
0161                        &key->source.addr6.s6_addr[0x4],
0162                        &key->source_mask.addr6.s6_addr[0x4], 4);
0163     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
0164                        &key->source.addr6.s6_addr[0x8],
0165                        &key->source_mask.addr6.s6_addr[0x8], 4);
0166     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0167                        &key->source.addr6.s6_addr[0xc],
0168                        &key->source_mask.addr6.s6_addr[0xc], 4);
0169     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
0170                        &key->group.addr6.s6_addr[0x0],
0171                        &key->group_mask.addr6.s6_addr[0x0], 4);
0172     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
0173                        &key->group.addr6.s6_addr[0x4],
0174                        &key->group_mask.addr6.s6_addr[0x4], 4);
0175     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
0176                        &key->group.addr6.s6_addr[0x8],
0177                        &key->group_mask.addr6.s6_addr[0x8], 4);
0178     mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
0179                        &key->group.addr6.s6_addr[0xc],
0180                        &key->group_mask.addr6.s6_addr[0xc], 4);
0181 }
0182 
0183 static void
0184 mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
0185                  struct mlxsw_sp_mr_route_key *key,
0186                  unsigned int priority)
0187 {
0188     struct mlxsw_sp_acl_rule_info *rulei;
0189 
0190     rulei = mlxsw_sp_acl_rule_rulei(rule);
0191     rulei->priority = priority;
0192     mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0193                        key->vrid, GENMASK(7, 0));
0194     mlxsw_sp_acl_rulei_keymask_u32(rulei,
0195                        MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0196                        key->vrid >> 8, GENMASK(2, 0));
0197     switch (key->proto) {
0198     case MLXSW_SP_L3_PROTO_IPV4:
0199         return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
0200     case MLXSW_SP_L3_PROTO_IPV6:
0201         return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
0202     }
0203 }
0204 
0205 static int
0206 mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
0207                    void *route_priv,
0208                    struct mlxsw_sp_mr_route_key *key,
0209                    struct mlxsw_afa_block *afa_block,
0210                    enum mlxsw_sp_mr_route_prio prio)
0211 {
0212     struct mlxsw_sp2_mr_route *mr_route = route_priv;
0213     struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0214     struct mlxsw_sp_acl_ruleset *ruleset;
0215     struct mlxsw_sp_acl_rule *rule;
0216     int err;
0217 
0218     mr_route->mr_tcam = mr_tcam;
0219     ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0220     if (WARN_ON(!ruleset))
0221         return -EINVAL;
0222 
0223     rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
0224                     (unsigned long) route_priv, afa_block,
0225                     NULL);
0226     if (IS_ERR(rule))
0227         return PTR_ERR(rule);
0228 
0229     mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
0230     err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
0231     if (err)
0232         goto err_rule_add;
0233 
0234     return 0;
0235 
0236 err_rule_add:
0237     mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
0238     return err;
0239 }
0240 
0241 static void
0242 mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
0243                 void *route_priv,
0244                 struct mlxsw_sp_mr_route_key *key)
0245 {
0246     struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0247     struct mlxsw_sp_acl_ruleset *ruleset;
0248     struct mlxsw_sp_acl_rule *rule;
0249 
0250     ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0251     if (WARN_ON(!ruleset))
0252         return;
0253 
0254     rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
0255                     (unsigned long) route_priv);
0256     if (WARN_ON(!rule))
0257         return;
0258 
0259     mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
0260     mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
0261 }
0262 
0263 static int
0264 mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
0265                    void *route_priv,
0266                    struct mlxsw_sp_mr_route_key *key,
0267                    struct mlxsw_afa_block *afa_block)
0268 {
0269     struct mlxsw_sp2_mr_route *mr_route = route_priv;
0270     struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
0271     struct mlxsw_sp_acl_ruleset *ruleset;
0272     struct mlxsw_sp_acl_rule *rule;
0273 
0274     ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0275     if (WARN_ON(!ruleset))
0276         return -EINVAL;
0277 
0278     rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
0279                     (unsigned long) route_priv);
0280     if (WARN_ON(!rule))
0281         return -EINVAL;
0282 
0283     return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
0284 }
0285 
0286 static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
0287 {
0288     struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0289     int err;
0290 
0291     mr_tcam->mlxsw_sp = mlxsw_sp;
0292     mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
0293     if (!mr_tcam->flow_block)
0294         return -ENOMEM;
0295 
0296     err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
0297     if (err)
0298         goto err_ipv4_init;
0299 
0300     err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
0301     if (err)
0302         goto err_ipv6_init;
0303 
0304     return 0;
0305 
0306 err_ipv6_init:
0307     mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
0308 err_ipv4_init:
0309     mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
0310     return err;
0311 }
0312 
0313 static void mlxsw_sp2_mr_tcam_fini(void *priv)
0314 {
0315     struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0316 
0317     mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
0318     mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
0319     mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
0320 }
0321 
0322 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
0323     .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
0324     .init = mlxsw_sp2_mr_tcam_init,
0325     .fini = mlxsw_sp2_mr_tcam_fini,
0326     .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
0327     .route_create = mlxsw_sp2_mr_tcam_route_create,
0328     .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
0329     .route_update = mlxsw_sp2_mr_tcam_route_update,
0330 };