brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · 99eeafd Raw
335 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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 10struct 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 17struct mlxsw_sp2_mr_route {18	struct mlxsw_sp2_mr_tcam *mr_tcam;19};20 21static struct mlxsw_sp_acl_ruleset *22mlxsw_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 34static 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 47static 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 53static 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 80err_bind_group:81	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);82	return err;83}84 85static 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 90static 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 104static 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 131err_bind_group:132	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);133	return err;134}135 136static 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 141static void142mlxsw_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 155static void156mlxsw_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 192static void193mlxsw_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 209static int210mlxsw_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 240err_rule_add:241	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);242	return err;243}244 245static void246mlxsw_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 267static int268mlxsw_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 290static 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 310err_ipv6_init:311	mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);312err_ipv4_init:313	mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);314	return err;315}316 317static 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 326const 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