335 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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,49 MLXSW_AFK_ELEMENT_SRC_IP_0_31,50 MLXSW_AFK_ELEMENT_DST_IP_0_31,51};52 53static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)54{55 struct mlxsw_afk_element_usage elusage;56 int err;57 58 /* Initialize IPv4 ACL group. */59 mlxsw_afk_element_usage_fill(&elusage,60 mlxsw_sp2_mr_tcam_usage_ipv4,61 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));62 mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,63 mr_tcam->flow_block,64 MLXSW_SP_L3_PROTO_IPV4,65 MLXSW_SP_ACL_PROFILE_MR,66 &elusage);67 68 if (IS_ERR(mr_tcam->ruleset4))69 return PTR_ERR(mr_tcam->ruleset4);70 71 /* MC Router groups should be bound before routes are inserted. */72 err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,73 MLXSW_REG_PEMRBT_PROTO_IPV4,74 mr_tcam->ruleset4);75 if (err)76 goto err_bind_group;77 78 return 0;79 80err_bind_group:81 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);82 return err;83}84 85static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)86{87 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);88}89 90static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {91 MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,92 MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,93 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,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 void142mlxsw_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_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER,146 key->vrid, GENMASK(11, 0));147 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,148 (char *) &key->source.addr4,149 (char *) &key->source_mask.addr4, 4);150 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,151 (char *) &key->group.addr4,152 (char *) &key->group_mask.addr4, 4);153}154 155static void156mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,157 struct mlxsw_sp_mr_route_key *key)158{159 mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,160 key->vrid, GENMASK(3, 0));161 mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,162 key->vrid >> 4, GENMASK(3, 0));163 mlxsw_sp_acl_rulei_keymask_u32(rulei,164 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,165 key->vrid >> 8, GENMASK(3, 0));166 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,167 &key->source.addr6.s6_addr[0x0],168 &key->source_mask.addr6.s6_addr[0x0], 4);169 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,170 &key->source.addr6.s6_addr[0x4],171 &key->source_mask.addr6.s6_addr[0x4], 4);172 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,173 &key->source.addr6.s6_addr[0x8],174 &key->source_mask.addr6.s6_addr[0x8], 4);175 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,176 &key->source.addr6.s6_addr[0xc],177 &key->source_mask.addr6.s6_addr[0xc], 4);178 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,179 &key->group.addr6.s6_addr[0x0],180 &key->group_mask.addr6.s6_addr[0x0], 4);181 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,182 &key->group.addr6.s6_addr[0x4],183 &key->group_mask.addr6.s6_addr[0x4], 4);184 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,185 &key->group.addr6.s6_addr[0x8],186 &key->group_mask.addr6.s6_addr[0x8], 4);187 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,188 &key->group.addr6.s6_addr[0xc],189 &key->group_mask.addr6.s6_addr[0xc], 4);190}191 192static void193mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,194 struct mlxsw_sp_mr_route_key *key,195 unsigned int priority)196{197 struct mlxsw_sp_acl_rule_info *rulei;198 199 rulei = mlxsw_sp_acl_rule_rulei(rule);200 rulei->priority = priority;201 switch (key->proto) {202 case MLXSW_SP_L3_PROTO_IPV4:203 return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);204 case MLXSW_SP_L3_PROTO_IPV6:205 return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);206 }207}208 209static int210mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,211 void *route_priv,212 struct mlxsw_sp_mr_route_key *key,213 struct mlxsw_afa_block *afa_block,214 enum mlxsw_sp_mr_route_prio prio)215{216 struct mlxsw_sp2_mr_route *mr_route = route_priv;217 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;218 struct mlxsw_sp_acl_ruleset *ruleset;219 struct mlxsw_sp_acl_rule *rule;220 int err;221 222 mr_route->mr_tcam = mr_tcam;223 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);224 if (WARN_ON(!ruleset))225 return -EINVAL;226 227 rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,228 (unsigned long) route_priv, afa_block,229 NULL);230 if (IS_ERR(rule))231 return PTR_ERR(rule);232 233 mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);234 err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);235 if (err)236 goto err_rule_add;237 238 return 0;239 240err_rule_add:241 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);242 return err;243}244 245static void246mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,247 void *route_priv,248 struct mlxsw_sp_mr_route_key *key)249{250 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;251 struct mlxsw_sp_acl_ruleset *ruleset;252 struct mlxsw_sp_acl_rule *rule;253 254 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);255 if (WARN_ON(!ruleset))256 return;257 258 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,259 (unsigned long) route_priv);260 if (WARN_ON(!rule))261 return;262 263 mlxsw_sp_acl_rule_del(mlxsw_sp, rule);264 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);265}266 267static int268mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,269 void *route_priv,270 struct mlxsw_sp_mr_route_key *key,271 struct mlxsw_afa_block *afa_block)272{273 struct mlxsw_sp2_mr_route *mr_route = route_priv;274 struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;275 struct mlxsw_sp_acl_ruleset *ruleset;276 struct mlxsw_sp_acl_rule *rule;277 278 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);279 if (WARN_ON(!ruleset))280 return -EINVAL;281 282 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,283 (unsigned long) route_priv);284 if (WARN_ON(!rule))285 return -EINVAL;286 287 return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);288}289 290static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)291{292 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;293 int err;294 295 mr_tcam->mlxsw_sp = mlxsw_sp;296 mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);297 if (!mr_tcam->flow_block)298 return -ENOMEM;299 300 err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);301 if (err)302 goto err_ipv4_init;303 304 err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);305 if (err)306 goto err_ipv6_init;307 308 return 0;309 310err_ipv6_init:311 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);312err_ipv4_init:313 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);314 return err;315}316 317static void mlxsw_sp2_mr_tcam_fini(void *priv)318{319 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;320 321 mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);322 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);323 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);324}325 326const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {327 .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),328 .init = mlxsw_sp2_mr_tcam_init,329 .fini = mlxsw_sp2_mr_tcam_fini,330 .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),331 .route_create = mlxsw_sp2_mr_tcam_route_create,332 .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,333 .route_update = mlxsw_sp2_mr_tcam_route_update,334};335