root/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp2_mr_tcam_proto_ruleset
  2. mlxsw_sp2_mr_tcam_bind_group
  3. mlxsw_sp2_mr_tcam_ipv4_init
  4. mlxsw_sp2_mr_tcam_ipv4_fini
  5. mlxsw_sp2_mr_tcam_ipv6_init
  6. mlxsw_sp2_mr_tcam_ipv6_fini
  7. mlxsw_sp2_mr_tcam_rule_parse4
  8. mlxsw_sp2_mr_tcam_rule_parse6
  9. mlxsw_sp2_mr_tcam_rule_parse
  10. mlxsw_sp2_mr_tcam_route_create
  11. mlxsw_sp2_mr_tcam_route_destroy
  12. mlxsw_sp2_mr_tcam_route_update
  13. mlxsw_sp2_mr_tcam_init
  14. mlxsw_sp2_mr_tcam_fini

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/kernel.h>
   5 
   6 #include "core_acl_flex_actions.h"
   7 #include "spectrum.h"
   8 #include "spectrum_mr.h"
   9 
  10 struct mlxsw_sp2_mr_tcam {
  11         struct mlxsw_sp *mlxsw_sp;
  12         struct mlxsw_sp_acl_block *acl_block;
  13         struct mlxsw_sp_acl_ruleset *ruleset4;
  14         struct mlxsw_sp_acl_ruleset *ruleset6;
  15 };
  16 
  17 struct mlxsw_sp2_mr_route {
  18         struct mlxsw_sp2_mr_tcam *mr_tcam;
  19 };
  20 
  21 static struct mlxsw_sp_acl_ruleset *
  22 mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
  23                                 enum mlxsw_sp_l3proto proto)
  24 {
  25         switch (proto) {
  26         case MLXSW_SP_L3_PROTO_IPV4:
  27                 return mr_tcam->ruleset4;
  28         case MLXSW_SP_L3_PROTO_IPV6:
  29                 return mr_tcam->ruleset6;
  30         }
  31         return NULL;
  32 }
  33 
  34 static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
  35                                         enum mlxsw_reg_pemrbt_protocol protocol,
  36                                         struct mlxsw_sp_acl_ruleset *ruleset)
  37 {
  38         char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
  39         u16 group_id;
  40 
  41         group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
  42 
  43         mlxsw_reg_pemrbt_pack(pemrbt_pl, protocol, group_id);
  44         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
  45 }
  46 
  47 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
  48                 MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
  49                 MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
  50                 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
  51                 MLXSW_AFK_ELEMENT_DST_IP_0_31,
  52 };
  53 
  54 static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
  55 {
  56         struct mlxsw_afk_element_usage elusage;
  57         int err;
  58 
  59         /* Initialize IPv4 ACL group. */
  60         mlxsw_afk_element_usage_fill(&elusage,
  61                                      mlxsw_sp2_mr_tcam_usage_ipv4,
  62                                      ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
  63         mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
  64                                                      mr_tcam->acl_block,
  65                                                      MLXSW_SP_L3_PROTO_IPV4,
  66                                                      MLXSW_SP_ACL_PROFILE_MR,
  67                                                      &elusage);
  68 
  69         if (IS_ERR(mr_tcam->ruleset4))
  70                 return PTR_ERR(mr_tcam->ruleset4);
  71 
  72         /* MC Router groups should be bound before routes are inserted. */
  73         err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
  74                                            MLXSW_REG_PEMRBT_PROTO_IPV4,
  75                                            mr_tcam->ruleset4);
  76         if (err)
  77                 goto err_bind_group;
  78 
  79         return 0;
  80 
  81 err_bind_group:
  82         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
  83         return err;
  84 }
  85 
  86 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
  87 {
  88         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
  89 }
  90 
  91 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
  92                 MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
  93                 MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
  94                 MLXSW_AFK_ELEMENT_SRC_IP_96_127,
  95                 MLXSW_AFK_ELEMENT_SRC_IP_64_95,
  96                 MLXSW_AFK_ELEMENT_SRC_IP_32_63,
  97                 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
  98                 MLXSW_AFK_ELEMENT_DST_IP_96_127,
  99                 MLXSW_AFK_ELEMENT_DST_IP_64_95,
 100                 MLXSW_AFK_ELEMENT_DST_IP_32_63,
 101                 MLXSW_AFK_ELEMENT_DST_IP_0_31,
 102 };
 103 
 104 static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
 105 {
 106         struct mlxsw_afk_element_usage elusage;
 107         int err;
 108 
 109         /* Initialize IPv6 ACL group */
 110         mlxsw_afk_element_usage_fill(&elusage,
 111                                      mlxsw_sp2_mr_tcam_usage_ipv6,
 112                                      ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
 113         mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
 114                                                      mr_tcam->acl_block,
 115                                                      MLXSW_SP_L3_PROTO_IPV6,
 116                                                      MLXSW_SP_ACL_PROFILE_MR,
 117                                                      &elusage);
 118 
 119         if (IS_ERR(mr_tcam->ruleset6))
 120                 return PTR_ERR(mr_tcam->ruleset6);
 121 
 122         /* MC Router groups should be bound before routes are inserted. */
 123         err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
 124                                            MLXSW_REG_PEMRBT_PROTO_IPV6,
 125                                            mr_tcam->ruleset6);
 126         if (err)
 127                 goto err_bind_group;
 128 
 129         return 0;
 130 
 131 err_bind_group:
 132         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
 133         return err;
 134 }
 135 
 136 static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
 137 {
 138         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
 139 }
 140 
 141 static void
 142 mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
 143                               struct mlxsw_sp_mr_route_key *key)
 144 {
 145         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
 146                                        (char *) &key->source.addr4,
 147                                        (char *) &key->source_mask.addr4, 4);
 148         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
 149                                        (char *) &key->group.addr4,
 150                                        (char *) &key->group_mask.addr4, 4);
 151 }
 152 
 153 static void
 154 mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
 155                               struct mlxsw_sp_mr_route_key *key)
 156 {
 157         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
 158                                        &key->source.addr6.s6_addr[0x0],
 159                                        &key->source_mask.addr6.s6_addr[0x0], 4);
 160         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
 161                                        &key->source.addr6.s6_addr[0x4],
 162                                        &key->source_mask.addr6.s6_addr[0x4], 4);
 163         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
 164                                        &key->source.addr6.s6_addr[0x8],
 165                                        &key->source_mask.addr6.s6_addr[0x8], 4);
 166         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
 167                                        &key->source.addr6.s6_addr[0xc],
 168                                        &key->source_mask.addr6.s6_addr[0xc], 4);
 169         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
 170                                        &key->group.addr6.s6_addr[0x0],
 171                                        &key->group_mask.addr6.s6_addr[0x0], 4);
 172         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
 173                                        &key->group.addr6.s6_addr[0x4],
 174                                        &key->group_mask.addr6.s6_addr[0x4], 4);
 175         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
 176                                        &key->group.addr6.s6_addr[0x8],
 177                                        &key->group_mask.addr6.s6_addr[0x8], 4);
 178         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
 179                                        &key->group.addr6.s6_addr[0xc],
 180                                        &key->group_mask.addr6.s6_addr[0xc], 4);
 181 }
 182 
 183 static void
 184 mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
 185                              struct mlxsw_sp_mr_route_key *key,
 186                              unsigned int priority)
 187 {
 188         struct mlxsw_sp_acl_rule_info *rulei;
 189 
 190         rulei = mlxsw_sp_acl_rule_rulei(rule);
 191         rulei->priority = priority;
 192         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
 193                                        key->vrid, GENMASK(7, 0));
 194         mlxsw_sp_acl_rulei_keymask_u32(rulei,
 195                                        MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
 196                                        key->vrid >> 8, GENMASK(2, 0));
 197         switch (key->proto) {
 198         case MLXSW_SP_L3_PROTO_IPV4:
 199                 return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
 200         case MLXSW_SP_L3_PROTO_IPV6:
 201                 return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
 202         }
 203 }
 204 
 205 static int
 206 mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
 207                                void *route_priv,
 208                                struct mlxsw_sp_mr_route_key *key,
 209                                struct mlxsw_afa_block *afa_block,
 210                                enum mlxsw_sp_mr_route_prio prio)
 211 {
 212         struct mlxsw_sp2_mr_route *mr_route = route_priv;
 213         struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
 214         struct mlxsw_sp_acl_ruleset *ruleset;
 215         struct mlxsw_sp_acl_rule *rule;
 216         int err;
 217 
 218         mr_route->mr_tcam = mr_tcam;
 219         ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
 220         if (WARN_ON(!ruleset))
 221                 return -EINVAL;
 222 
 223         rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
 224                                         (unsigned long) route_priv, afa_block,
 225                                         NULL);
 226         if (IS_ERR(rule))
 227                 return PTR_ERR(rule);
 228 
 229         mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
 230         err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
 231         if (err)
 232                 goto err_rule_add;
 233 
 234         return 0;
 235 
 236 err_rule_add:
 237         mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
 238         return err;
 239 }
 240 
 241 static void
 242 mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
 243                                 void *route_priv,
 244                                 struct mlxsw_sp_mr_route_key *key)
 245 {
 246         struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
 247         struct mlxsw_sp_acl_ruleset *ruleset;
 248         struct mlxsw_sp_acl_rule *rule;
 249 
 250         ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
 251         if (WARN_ON(!ruleset))
 252                 return;
 253 
 254         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
 255                                         (unsigned long) route_priv);
 256         if (WARN_ON(!rule))
 257                 return;
 258 
 259         mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
 260         mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
 261 }
 262 
 263 static int
 264 mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
 265                                void *route_priv,
 266                                struct mlxsw_sp_mr_route_key *key,
 267                                struct mlxsw_afa_block *afa_block)
 268 {
 269         struct mlxsw_sp2_mr_route *mr_route = route_priv;
 270         struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
 271         struct mlxsw_sp_acl_ruleset *ruleset;
 272         struct mlxsw_sp_acl_rule *rule;
 273 
 274         ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
 275         if (WARN_ON(!ruleset))
 276                 return -EINVAL;
 277 
 278         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
 279                                         (unsigned long) route_priv);
 280         if (WARN_ON(!rule))
 281                 return -EINVAL;
 282 
 283         return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
 284 }
 285 
 286 static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
 287 {
 288         struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
 289         int err;
 290 
 291         mr_tcam->mlxsw_sp = mlxsw_sp;
 292         mr_tcam->acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, NULL);
 293         if (!mr_tcam->acl_block)
 294                 return -ENOMEM;
 295 
 296         err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
 297         if (err)
 298                 goto err_ipv4_init;
 299 
 300         err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
 301         if (err)
 302                 goto err_ipv6_init;
 303 
 304         return 0;
 305 
 306 err_ipv6_init:
 307         mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
 308 err_ipv4_init:
 309         mlxsw_sp_acl_block_destroy(mr_tcam->acl_block);
 310         return err;
 311 }
 312 
 313 static void mlxsw_sp2_mr_tcam_fini(void *priv)
 314 {
 315         struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
 316 
 317         mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
 318         mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
 319         mlxsw_sp_acl_block_destroy(mr_tcam->acl_block);
 320 }
 321 
 322 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
 323         .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
 324         .init = mlxsw_sp2_mr_tcam_init,
 325         .fini = mlxsw_sp2_mr_tcam_fini,
 326         .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
 327         .route_create = mlxsw_sp2_mr_tcam_route_create,
 328         .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
 329         .route_update = mlxsw_sp2_mr_tcam_route_update,
 330 };

/* [<][>][^][v][top][bottom][index][help] */