spectrum2_mr_tcam.c (9812B)
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_MSB, 49 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, 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_MSB, 93 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, 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_LSB, 193 key->vrid, GENMASK(7, 0)); 194 mlxsw_sp_acl_rulei_keymask_u32(rulei, 195 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, 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};