.. | .. |
---|
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, |
---|