0001
0002
0003
0004 #include <linux/kernel.h>
0005
0006 #include "core_acl_flex_actions.h"
0007 #include "spectrum.h"
0008 #include "spectrum_mr.h"
0009
0010 struct mlxsw_sp2_mr_tcam {
0011 struct mlxsw_sp *mlxsw_sp;
0012 struct mlxsw_sp_flow_block *flow_block;
0013 struct mlxsw_sp_acl_ruleset *ruleset4;
0014 struct mlxsw_sp_acl_ruleset *ruleset6;
0015 };
0016
0017 struct mlxsw_sp2_mr_route {
0018 struct mlxsw_sp2_mr_tcam *mr_tcam;
0019 };
0020
0021 static struct mlxsw_sp_acl_ruleset *
0022 mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
0023 enum mlxsw_sp_l3proto proto)
0024 {
0025 switch (proto) {
0026 case MLXSW_SP_L3_PROTO_IPV4:
0027 return mr_tcam->ruleset4;
0028 case MLXSW_SP_L3_PROTO_IPV6:
0029 return mr_tcam->ruleset6;
0030 }
0031 return NULL;
0032 }
0033
0034 static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
0035 enum mlxsw_reg_pemrbt_protocol protocol,
0036 struct mlxsw_sp_acl_ruleset *ruleset)
0037 {
0038 char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
0039 u16 group_id;
0040
0041 group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
0042
0043 mlxsw_reg_pemrbt_pack(pemrbt_pl, protocol, group_id);
0044 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
0045 }
0046
0047 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
0048 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0049 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0050 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0051 MLXSW_AFK_ELEMENT_DST_IP_0_31,
0052 };
0053
0054 static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
0055 {
0056 struct mlxsw_afk_element_usage elusage;
0057 int err;
0058
0059
0060 mlxsw_afk_element_usage_fill(&elusage,
0061 mlxsw_sp2_mr_tcam_usage_ipv4,
0062 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
0063 mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
0064 mr_tcam->flow_block,
0065 MLXSW_SP_L3_PROTO_IPV4,
0066 MLXSW_SP_ACL_PROFILE_MR,
0067 &elusage);
0068
0069 if (IS_ERR(mr_tcam->ruleset4))
0070 return PTR_ERR(mr_tcam->ruleset4);
0071
0072
0073 err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
0074 MLXSW_REG_PEMRBT_PROTO_IPV4,
0075 mr_tcam->ruleset4);
0076 if (err)
0077 goto err_bind_group;
0078
0079 return 0;
0080
0081 err_bind_group:
0082 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
0083 return err;
0084 }
0085
0086 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
0087 {
0088 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
0089 }
0090
0091 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
0092 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0093 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0094 MLXSW_AFK_ELEMENT_SRC_IP_96_127,
0095 MLXSW_AFK_ELEMENT_SRC_IP_64_95,
0096 MLXSW_AFK_ELEMENT_SRC_IP_32_63,
0097 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0098 MLXSW_AFK_ELEMENT_DST_IP_96_127,
0099 MLXSW_AFK_ELEMENT_DST_IP_64_95,
0100 MLXSW_AFK_ELEMENT_DST_IP_32_63,
0101 MLXSW_AFK_ELEMENT_DST_IP_0_31,
0102 };
0103
0104 static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
0105 {
0106 struct mlxsw_afk_element_usage elusage;
0107 int err;
0108
0109
0110 mlxsw_afk_element_usage_fill(&elusage,
0111 mlxsw_sp2_mr_tcam_usage_ipv6,
0112 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
0113 mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
0114 mr_tcam->flow_block,
0115 MLXSW_SP_L3_PROTO_IPV6,
0116 MLXSW_SP_ACL_PROFILE_MR,
0117 &elusage);
0118
0119 if (IS_ERR(mr_tcam->ruleset6))
0120 return PTR_ERR(mr_tcam->ruleset6);
0121
0122
0123 err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
0124 MLXSW_REG_PEMRBT_PROTO_IPV6,
0125 mr_tcam->ruleset6);
0126 if (err)
0127 goto err_bind_group;
0128
0129 return 0;
0130
0131 err_bind_group:
0132 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
0133 return err;
0134 }
0135
0136 static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
0137 {
0138 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
0139 }
0140
0141 static void
0142 mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
0143 struct mlxsw_sp_mr_route_key *key)
0144 {
0145 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0146 (char *) &key->source.addr4,
0147 (char *) &key->source_mask.addr4, 4);
0148 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
0149 (char *) &key->group.addr4,
0150 (char *) &key->group_mask.addr4, 4);
0151 }
0152
0153 static void
0154 mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
0155 struct mlxsw_sp_mr_route_key *key)
0156 {
0157 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
0158 &key->source.addr6.s6_addr[0x0],
0159 &key->source_mask.addr6.s6_addr[0x0], 4);
0160 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
0161 &key->source.addr6.s6_addr[0x4],
0162 &key->source_mask.addr6.s6_addr[0x4], 4);
0163 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
0164 &key->source.addr6.s6_addr[0x8],
0165 &key->source_mask.addr6.s6_addr[0x8], 4);
0166 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
0167 &key->source.addr6.s6_addr[0xc],
0168 &key->source_mask.addr6.s6_addr[0xc], 4);
0169 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
0170 &key->group.addr6.s6_addr[0x0],
0171 &key->group_mask.addr6.s6_addr[0x0], 4);
0172 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
0173 &key->group.addr6.s6_addr[0x4],
0174 &key->group_mask.addr6.s6_addr[0x4], 4);
0175 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
0176 &key->group.addr6.s6_addr[0x8],
0177 &key->group_mask.addr6.s6_addr[0x8], 4);
0178 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
0179 &key->group.addr6.s6_addr[0xc],
0180 &key->group_mask.addr6.s6_addr[0xc], 4);
0181 }
0182
0183 static void
0184 mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
0185 struct mlxsw_sp_mr_route_key *key,
0186 unsigned int priority)
0187 {
0188 struct mlxsw_sp_acl_rule_info *rulei;
0189
0190 rulei = mlxsw_sp_acl_rule_rulei(rule);
0191 rulei->priority = priority;
0192 mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
0193 key->vrid, GENMASK(7, 0));
0194 mlxsw_sp_acl_rulei_keymask_u32(rulei,
0195 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
0196 key->vrid >> 8, GENMASK(2, 0));
0197 switch (key->proto) {
0198 case MLXSW_SP_L3_PROTO_IPV4:
0199 return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
0200 case MLXSW_SP_L3_PROTO_IPV6:
0201 return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
0202 }
0203 }
0204
0205 static int
0206 mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
0207 void *route_priv,
0208 struct mlxsw_sp_mr_route_key *key,
0209 struct mlxsw_afa_block *afa_block,
0210 enum mlxsw_sp_mr_route_prio prio)
0211 {
0212 struct mlxsw_sp2_mr_route *mr_route = route_priv;
0213 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0214 struct mlxsw_sp_acl_ruleset *ruleset;
0215 struct mlxsw_sp_acl_rule *rule;
0216 int err;
0217
0218 mr_route->mr_tcam = mr_tcam;
0219 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0220 if (WARN_ON(!ruleset))
0221 return -EINVAL;
0222
0223 rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
0224 (unsigned long) route_priv, afa_block,
0225 NULL);
0226 if (IS_ERR(rule))
0227 return PTR_ERR(rule);
0228
0229 mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
0230 err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
0231 if (err)
0232 goto err_rule_add;
0233
0234 return 0;
0235
0236 err_rule_add:
0237 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
0238 return err;
0239 }
0240
0241 static void
0242 mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
0243 void *route_priv,
0244 struct mlxsw_sp_mr_route_key *key)
0245 {
0246 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0247 struct mlxsw_sp_acl_ruleset *ruleset;
0248 struct mlxsw_sp_acl_rule *rule;
0249
0250 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0251 if (WARN_ON(!ruleset))
0252 return;
0253
0254 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
0255 (unsigned long) route_priv);
0256 if (WARN_ON(!rule))
0257 return;
0258
0259 mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
0260 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
0261 }
0262
0263 static int
0264 mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
0265 void *route_priv,
0266 struct mlxsw_sp_mr_route_key *key,
0267 struct mlxsw_afa_block *afa_block)
0268 {
0269 struct mlxsw_sp2_mr_route *mr_route = route_priv;
0270 struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
0271 struct mlxsw_sp_acl_ruleset *ruleset;
0272 struct mlxsw_sp_acl_rule *rule;
0273
0274 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
0275 if (WARN_ON(!ruleset))
0276 return -EINVAL;
0277
0278 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
0279 (unsigned long) route_priv);
0280 if (WARN_ON(!rule))
0281 return -EINVAL;
0282
0283 return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
0284 }
0285
0286 static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
0287 {
0288 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0289 int err;
0290
0291 mr_tcam->mlxsw_sp = mlxsw_sp;
0292 mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
0293 if (!mr_tcam->flow_block)
0294 return -ENOMEM;
0295
0296 err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
0297 if (err)
0298 goto err_ipv4_init;
0299
0300 err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
0301 if (err)
0302 goto err_ipv6_init;
0303
0304 return 0;
0305
0306 err_ipv6_init:
0307 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
0308 err_ipv4_init:
0309 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
0310 return err;
0311 }
0312
0313 static void mlxsw_sp2_mr_tcam_fini(void *priv)
0314 {
0315 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
0316
0317 mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
0318 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
0319 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
0320 }
0321
0322 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
0323 .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
0324 .init = mlxsw_sp2_mr_tcam_init,
0325 .fini = mlxsw_sp2_mr_tcam_fini,
0326 .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
0327 .route_create = mlxsw_sp2_mr_tcam_route_create,
0328 .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
0329 .route_update = mlxsw_sp2_mr_tcam_route_update,
0330 };