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_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 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->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 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_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 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_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_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(3, 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->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 306 err_ipv6_init: 307 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam); 308 err_ipv4_init: 309 mlxsw_sp_flow_block_destroy(mr_tcam->flow_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_flow_block_destroy(mr_tcam->flow_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 }; 331