| .. | .. |
|---|
| 7 | 7 | #include "spectrum.h" |
|---|
| 8 | 8 | #include "spectrum_mr.h" |
|---|
| 9 | 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_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 | + |
|---|
| 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_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 | + |
|---|
| 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_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 | + |
|---|
| 10 | 205 | static int |
|---|
| 11 | 206 | mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv, |
|---|
| 12 | 207 | void *route_priv, |
|---|
| .. | .. |
|---|
| 14 | 209 | struct mlxsw_afa_block *afa_block, |
|---|
| 15 | 210 | enum mlxsw_sp_mr_route_prio prio) |
|---|
| 16 | 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 | + |
|---|
| 17 | 234 | return 0; |
|---|
| 235 | + |
|---|
| 236 | +err_rule_add: |
|---|
| 237 | + mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule); |
|---|
| 238 | + return err; |
|---|
| 18 | 239 | } |
|---|
| 19 | 240 | |
|---|
| 20 | 241 | static void |
|---|
| .. | .. |
|---|
| 22 | 243 | void *route_priv, |
|---|
| 23 | 244 | struct mlxsw_sp_mr_route_key *key) |
|---|
| 24 | 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); |
|---|
| 25 | 261 | } |
|---|
| 26 | 262 | |
|---|
| 27 | 263 | static int |
|---|
| .. | .. |
|---|
| 30 | 266 | struct mlxsw_sp_mr_route_key *key, |
|---|
| 31 | 267 | struct mlxsw_afa_block *afa_block) |
|---|
| 32 | 268 | { |
|---|
| 33 | | - return 0; |
|---|
| 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); |
|---|
| 34 | 284 | } |
|---|
| 35 | 285 | |
|---|
| 36 | 286 | static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv) |
|---|
| 37 | 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 | + |
|---|
| 38 | 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; |
|---|
| 39 | 311 | } |
|---|
| 40 | 312 | |
|---|
| 41 | 313 | static void mlxsw_sp2_mr_tcam_fini(void *priv) |
|---|
| 42 | 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); |
|---|
| 43 | 320 | } |
|---|
| 44 | 321 | |
|---|
| 45 | 322 | const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = { |
|---|
| 323 | + .priv_size = sizeof(struct mlxsw_sp2_mr_tcam), |
|---|
| 46 | 324 | .init = mlxsw_sp2_mr_tcam_init, |
|---|
| 47 | 325 | .fini = mlxsw_sp2_mr_tcam_fini, |
|---|
| 326 | + .route_priv_size = sizeof(struct mlxsw_sp2_mr_route), |
|---|
| 48 | 327 | .route_create = mlxsw_sp2_mr_tcam_route_create, |
|---|
| 49 | 328 | .route_destroy = mlxsw_sp2_mr_tcam_route_destroy, |
|---|
| 50 | 329 | .route_update = mlxsw_sp2_mr_tcam_route_update, |
|---|