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_flow_block *flow_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, 49 MLXSW_AFK_ELEMENT_SRC_IP_0_31, 50 MLXSW_AFK_ELEMENT_DST_IP_0_31, 51 }; 52 53 static 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 80 err_bind_group: 81 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4); 82 return err; 83 } 84 85 static 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 90 static 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 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->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 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_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 155 static void 156 mlxsw_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 192 static void 193 mlxsw_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 209 static int 210 mlxsw_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 240 err_rule_add: 241 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule); 242 return err; 243 } 244 245 static void 246 mlxsw_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 267 static int 268 mlxsw_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 290 static 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 310 err_ipv6_init: 311 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam); 312 err_ipv4_init: 313 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block); 314 return err; 315 } 316 317 static 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 326 const 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