linux/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c
<<
>>
Prefs
   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
  10struct mlxsw_sp2_mr_tcam {
  11        struct mlxsw_sp *mlxsw_sp;
  12        struct mlxsw_sp_flow_block *flow_block;
  13        struct mlxsw_sp_acl_ruleset *ruleset4;
  14        struct mlxsw_sp_acl_ruleset *ruleset6;
  15};
  16
  17struct mlxsw_sp2_mr_route {
  18        struct mlxsw_sp2_mr_tcam *mr_tcam;
  19};
  20
  21static struct mlxsw_sp_acl_ruleset *
  22mlxsw_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
  34static 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
  47static 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
  54static 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->flow_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
  81err_bind_group:
  82        mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
  83        return err;
  84}
  85
  86static 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
  91static 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
 104static 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->flow_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
 131err_bind_group:
 132        mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
 133        return err;
 134}
 135
 136static 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
 141static void
 142mlxsw_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
 153static void
 154mlxsw_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
 183static void
 184mlxsw_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
 205static int
 206mlxsw_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
 236err_rule_add:
 237        mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
 238        return err;
 239}
 240
 241static void
 242mlxsw_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
 263static int
 264mlxsw_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
 286static 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->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
 293        if (!mr_tcam->flow_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
 306err_ipv6_init:
 307        mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
 308err_ipv4_init:
 309        mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
 310        return err;
 311}
 312
 313static 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_flow_block_destroy(mr_tcam->flow_block);
 320}
 321
 322const 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};
 331