mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-15 18:46:47 +07:00
Merge branch 'mlxsw-Add-Spectrum-2-multicast-routing-support'
Ido Schimmel says: ==================== mlxsw: Add Spectrum-2 multicast routing support Nir says: In Spectrum the firmware provided an abstraction for multicast routing on top of the policy engine. In Spectrum-2 this is no longer the case and the driver must interact directly with the policy engine in order to program multicast routes. Every route is written as an ACL rule, its priority set according to route type (*,G) or (S,G) and its action is an appropriate multicast routing action. Multicast routes are written to a specific ACL group which is bound to the appropriate IP protocol IPv4/IPv6. Patch #1 adds PEMRBT register needed to declare which ACL group is dedicated for each IP protocol multicast routing function. Patch #2 Changes initialization order and puts ACL before router as multicast router now uses ACL module. Patch #3 adds Spectrum-2 ACL keys needed for multicast route matching. Patch #4 adds another ACL profile - in addition to existing flower profile - which allows the multicast routing module to program rules directly into the ACL block. Patch #5 adds the ability to update ACL rules' action, since multicast routes actions may be updated after being configured. Patch #6 separates rule creation operation and rule action creation operation as in multicast router the action is created before the route is inserted. Patch #7 sharpens priority handling in Spectrum-2, to ensure incorrect values are not set to rule's priority. Patch #8 adds the implementation of multicast routing for IPv4 and IPv6 over existing ACL rule programming Finally, patch #9 adds a test for IPv4/IPv6 multicast routing. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3f9b7eeea0
@ -33,6 +33,8 @@ enum mlxsw_afk_element {
|
||||
MLXSW_AFK_ELEMENT_IP_TTL_,
|
||||
MLXSW_AFK_ELEMENT_IP_ECN,
|
||||
MLXSW_AFK_ELEMENT_IP_DSCP,
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
|
||||
MLXSW_AFK_ELEMENT_MAX,
|
||||
};
|
||||
|
||||
@ -87,6 +89,8 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
|
||||
MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8),
|
||||
MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2),
|
||||
MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6),
|
||||
MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_8_10, 0x18, 17, 3),
|
||||
MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_0_7, 0x18, 20, 8),
|
||||
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_96_127, 0x20, 4),
|
||||
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_64_95, 0x24, 4),
|
||||
MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_32_63, 0x28, 4),
|
||||
|
@ -2495,6 +2495,43 @@ static inline void mlxsw_reg_pefa_unpack(char *payload, bool *p_a)
|
||||
*p_a = mlxsw_reg_pefa_a_get(payload);
|
||||
}
|
||||
|
||||
/* PEMRBT - Policy-Engine Multicast Router Binding Table Register
|
||||
* --------------------------------------------------------------
|
||||
* This register is used for binding Multicast router to an ACL group
|
||||
* that serves the MC router.
|
||||
* This register is not supported by SwitchX/-2 and Spectrum.
|
||||
*/
|
||||
#define MLXSW_REG_PEMRBT_ID 0x3014
|
||||
#define MLXSW_REG_PEMRBT_LEN 0x14
|
||||
|
||||
MLXSW_REG_DEFINE(pemrbt, MLXSW_REG_PEMRBT_ID, MLXSW_REG_PEMRBT_LEN);
|
||||
|
||||
enum mlxsw_reg_pemrbt_protocol {
|
||||
MLXSW_REG_PEMRBT_PROTO_IPV4,
|
||||
MLXSW_REG_PEMRBT_PROTO_IPV6,
|
||||
};
|
||||
|
||||
/* reg_pemrbt_protocol
|
||||
* Access: Index
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pemrbt, protocol, 0x00, 0, 1);
|
||||
|
||||
/* reg_pemrbt_group_id
|
||||
* ACL group identifier.
|
||||
* Range 0..cap_max_acl_groups-1
|
||||
* Access: RW
|
||||
*/
|
||||
MLXSW_ITEM32(reg, pemrbt, group_id, 0x10, 0, 16);
|
||||
|
||||
static inline void
|
||||
mlxsw_reg_pemrbt_pack(char *payload, enum mlxsw_reg_pemrbt_protocol protocol,
|
||||
u16 group_id)
|
||||
{
|
||||
MLXSW_REG_ZERO(pemrbt, payload);
|
||||
mlxsw_reg_pemrbt_protocol_set(payload, protocol);
|
||||
mlxsw_reg_pemrbt_group_id_set(payload, group_id);
|
||||
}
|
||||
|
||||
/* PTCE-V2 - Policy-Engine TCAM Entry Register Version 2
|
||||
* -----------------------------------------------------
|
||||
* This register is used for accessing rules within a TCAM region.
|
||||
@ -9568,6 +9605,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
|
||||
MLXSW_REG(ppbs),
|
||||
MLXSW_REG(prcr),
|
||||
MLXSW_REG(pefa),
|
||||
MLXSW_REG(pemrbt),
|
||||
MLXSW_REG(ptce2),
|
||||
MLXSW_REG(perpt),
|
||||
MLXSW_REG(perar),
|
||||
|
@ -4002,6 +4002,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
|
||||
goto err_nve_init;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_acl_init(mlxsw_sp);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
|
||||
goto err_acl_init;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_router_init(mlxsw_sp);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
|
||||
@ -4019,12 +4025,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
|
||||
goto err_netdev_notifier;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_acl_init(mlxsw_sp);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
|
||||
goto err_acl_init;
|
||||
}
|
||||
|
||||
err = mlxsw_sp_dpipe_init(mlxsw_sp);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n");
|
||||
@ -4042,12 +4042,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
|
||||
err_ports_create:
|
||||
mlxsw_sp_dpipe_fini(mlxsw_sp);
|
||||
err_dpipe_init:
|
||||
mlxsw_sp_acl_fini(mlxsw_sp);
|
||||
err_acl_init:
|
||||
unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
|
||||
err_netdev_notifier:
|
||||
mlxsw_sp_router_fini(mlxsw_sp);
|
||||
err_router_init:
|
||||
mlxsw_sp_acl_fini(mlxsw_sp);
|
||||
err_acl_init:
|
||||
mlxsw_sp_nve_fini(mlxsw_sp);
|
||||
err_nve_init:
|
||||
mlxsw_sp_afa_fini(mlxsw_sp);
|
||||
@ -4108,9 +4108,9 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
|
||||
|
||||
mlxsw_sp_ports_remove(mlxsw_sp);
|
||||
mlxsw_sp_dpipe_fini(mlxsw_sp);
|
||||
mlxsw_sp_acl_fini(mlxsw_sp);
|
||||
unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
|
||||
mlxsw_sp_router_fini(mlxsw_sp);
|
||||
mlxsw_sp_acl_fini(mlxsw_sp);
|
||||
mlxsw_sp_nve_fini(mlxsw_sp);
|
||||
mlxsw_sp_afa_fini(mlxsw_sp);
|
||||
mlxsw_sp_counter_pool_fini(mlxsw_sp);
|
||||
|
@ -563,6 +563,7 @@ struct mlxsw_sp_acl_rule_info {
|
||||
unsigned int priority;
|
||||
struct mlxsw_afk_element_values values;
|
||||
struct mlxsw_afa_block *act_block;
|
||||
u8 action_created:1;
|
||||
unsigned int counter_index;
|
||||
};
|
||||
|
||||
@ -572,6 +573,7 @@ struct mlxsw_sp_acl_ruleset;
|
||||
/* spectrum_acl.c */
|
||||
enum mlxsw_sp_acl_profile {
|
||||
MLXSW_SP_ACL_PROFILE_FLOWER,
|
||||
MLXSW_SP_ACL_PROFILE_MR,
|
||||
};
|
||||
|
||||
struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
|
||||
@ -606,7 +608,8 @@ void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
|
||||
u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset);
|
||||
|
||||
struct mlxsw_sp_acl_rule_info *
|
||||
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl);
|
||||
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
|
||||
struct mlxsw_afa_block *afa_block);
|
||||
void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei);
|
||||
int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei);
|
||||
void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
|
||||
@ -650,6 +653,7 @@ struct mlxsw_sp_acl_rule *
|
||||
mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ruleset *ruleset,
|
||||
unsigned long cookie,
|
||||
struct mlxsw_afa_block *afa_block,
|
||||
struct netlink_ext_ack *extack);
|
||||
void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_rule *rule);
|
||||
@ -657,6 +661,9 @@ int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_rule *rule);
|
||||
void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_rule *rule);
|
||||
int mlxsw_sp_acl_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_rule *rule,
|
||||
struct mlxsw_afa_block *afa_block);
|
||||
struct mlxsw_sp_acl_rule *
|
||||
mlxsw_sp_acl_rule_lookup(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ruleset *ruleset,
|
||||
@ -701,6 +708,10 @@ struct mlxsw_sp_acl_tcam_ops {
|
||||
void (*entry_del)(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *chunk_priv,
|
||||
void *entry_priv);
|
||||
int (*entry_action_replace)(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *chunk_priv,
|
||||
void *entry_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei);
|
||||
int (*entry_activity_get)(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *entry_priv,
|
||||
bool *activity);
|
||||
|
@ -67,7 +67,7 @@ mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp,
|
||||
mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion,
|
||||
®ion->catchall.cchunk,
|
||||
MLXSW_SP_ACL_TCAM_CATCHALL_PRIO);
|
||||
rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl);
|
||||
rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, NULL);
|
||||
if (IS_ERR(rulei)) {
|
||||
err = PTR_ERR(rulei);
|
||||
goto err_rulei_create;
|
||||
@ -192,6 +192,15 @@ static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
&chunk->cchunk, &entry->centry);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp1_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *chunk_priv,
|
||||
void *entry_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_region *_region,
|
||||
@ -240,5 +249,6 @@ const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = {
|
||||
.entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry),
|
||||
.entry_add = mlxsw_sp1_acl_tcam_entry_add,
|
||||
.entry_del = mlxsw_sp1_acl_tcam_entry_del,
|
||||
.entry_action_replace = mlxsw_sp1_acl_tcam_entry_action_replace,
|
||||
.entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get,
|
||||
};
|
||||
|
@ -210,6 +210,23 @@ static void mlxsw_sp2_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
&entry->aentry);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp2_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *chunk_priv,
|
||||
void *entry_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
struct mlxsw_sp2_acl_tcam_region *region = region_priv;
|
||||
struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
|
||||
struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
|
||||
|
||||
entry->act_block = rulei->act_block;
|
||||
return mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp,
|
||||
®ion->aregion,
|
||||
&chunk->achunk,
|
||||
&entry->aentry, rulei);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp2_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
void *region_priv, void *entry_priv,
|
||||
@ -235,5 +252,6 @@ const struct mlxsw_sp_acl_tcam_ops mlxsw_sp2_acl_tcam_ops = {
|
||||
.entry_priv_size = sizeof(struct mlxsw_sp2_acl_tcam_entry),
|
||||
.entry_add = mlxsw_sp2_acl_tcam_entry_add,
|
||||
.entry_del = mlxsw_sp2_acl_tcam_entry_del,
|
||||
.entry_action_replace = mlxsw_sp2_acl_tcam_entry_action_replace,
|
||||
.entry_activity_get = mlxsw_sp2_acl_tcam_entry_activity_get,
|
||||
};
|
||||
|
@ -7,6 +7,201 @@
|
||||
#include "spectrum.h"
|
||||
#include "spectrum_mr.h"
|
||||
|
||||
struct mlxsw_sp2_mr_tcam {
|
||||
struct mlxsw_sp *mlxsw_sp;
|
||||
struct mlxsw_sp_acl_block *acl_block;
|
||||
struct mlxsw_sp_acl_ruleset *ruleset4;
|
||||
struct mlxsw_sp_acl_ruleset *ruleset6;
|
||||
};
|
||||
|
||||
struct mlxsw_sp2_mr_route {
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam;
|
||||
};
|
||||
|
||||
static struct mlxsw_sp_acl_ruleset *
|
||||
mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
|
||||
enum mlxsw_sp_l3proto proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case MLXSW_SP_L3_PROTO_IPV4:
|
||||
return mr_tcam->ruleset4;
|
||||
case MLXSW_SP_L3_PROTO_IPV6:
|
||||
return mr_tcam->ruleset6;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
|
||||
enum mlxsw_reg_pemrbt_protocol protocol,
|
||||
struct mlxsw_sp_acl_ruleset *ruleset)
|
||||
{
|
||||
char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
|
||||
u16 group_id;
|
||||
|
||||
group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
|
||||
|
||||
mlxsw_reg_pemrbt_pack(pemrbt_pl, protocol, group_id);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
|
||||
}
|
||||
|
||||
static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
|
||||
MLXSW_AFK_ELEMENT_SRC_IP_0_31,
|
||||
MLXSW_AFK_ELEMENT_DST_IP_0_31,
|
||||
};
|
||||
|
||||
static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
|
||||
{
|
||||
struct mlxsw_afk_element_usage elusage;
|
||||
int err;
|
||||
|
||||
/* Initialize IPv4 ACL group. */
|
||||
mlxsw_afk_element_usage_fill(&elusage,
|
||||
mlxsw_sp2_mr_tcam_usage_ipv4,
|
||||
ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
|
||||
mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
|
||||
mr_tcam->acl_block,
|
||||
MLXSW_SP_L3_PROTO_IPV4,
|
||||
MLXSW_SP_ACL_PROFILE_MR,
|
||||
&elusage);
|
||||
|
||||
if (IS_ERR(mr_tcam->ruleset4))
|
||||
return PTR_ERR(mr_tcam->ruleset4);
|
||||
|
||||
/* MC Router groups should be bound before routes are inserted. */
|
||||
err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
|
||||
MLXSW_REG_PEMRBT_PROTO_IPV4,
|
||||
mr_tcam->ruleset4);
|
||||
if (err)
|
||||
goto err_bind_group;
|
||||
|
||||
return 0;
|
||||
|
||||
err_bind_group:
|
||||
mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
|
||||
{
|
||||
mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
|
||||
}
|
||||
|
||||
static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
|
||||
MLXSW_AFK_ELEMENT_SRC_IP_96_127,
|
||||
MLXSW_AFK_ELEMENT_SRC_IP_64_95,
|
||||
MLXSW_AFK_ELEMENT_SRC_IP_32_63,
|
||||
MLXSW_AFK_ELEMENT_SRC_IP_0_31,
|
||||
MLXSW_AFK_ELEMENT_DST_IP_96_127,
|
||||
MLXSW_AFK_ELEMENT_DST_IP_64_95,
|
||||
MLXSW_AFK_ELEMENT_DST_IP_32_63,
|
||||
MLXSW_AFK_ELEMENT_DST_IP_0_31,
|
||||
};
|
||||
|
||||
static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
|
||||
{
|
||||
struct mlxsw_afk_element_usage elusage;
|
||||
int err;
|
||||
|
||||
/* Initialize IPv6 ACL group */
|
||||
mlxsw_afk_element_usage_fill(&elusage,
|
||||
mlxsw_sp2_mr_tcam_usage_ipv6,
|
||||
ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
|
||||
mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
|
||||
mr_tcam->acl_block,
|
||||
MLXSW_SP_L3_PROTO_IPV6,
|
||||
MLXSW_SP_ACL_PROFILE_MR,
|
||||
&elusage);
|
||||
|
||||
if (IS_ERR(mr_tcam->ruleset6))
|
||||
return PTR_ERR(mr_tcam->ruleset6);
|
||||
|
||||
/* MC Router groups should be bound before routes are inserted. */
|
||||
err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
|
||||
MLXSW_REG_PEMRBT_PROTO_IPV6,
|
||||
mr_tcam->ruleset6);
|
||||
if (err)
|
||||
goto err_bind_group;
|
||||
|
||||
return 0;
|
||||
|
||||
err_bind_group:
|
||||
mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
|
||||
{
|
||||
mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
|
||||
struct mlxsw_sp_mr_route_key *key)
|
||||
{
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
|
||||
(char *) &key->source.addr4,
|
||||
(char *) &key->source_mask.addr4, 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
|
||||
(char *) &key->group.addr4,
|
||||
(char *) &key->group_mask.addr4, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
|
||||
struct mlxsw_sp_mr_route_key *key)
|
||||
{
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
|
||||
&key->source.addr6.s6_addr[0x0],
|
||||
&key->source_mask.addr6.s6_addr[0x0], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
|
||||
&key->source.addr6.s6_addr[0x4],
|
||||
&key->source_mask.addr6.s6_addr[0x4], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
|
||||
&key->source.addr6.s6_addr[0x8],
|
||||
&key->source_mask.addr6.s6_addr[0x8], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
|
||||
&key->source.addr6.s6_addr[0xc],
|
||||
&key->source_mask.addr6.s6_addr[0xc], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
|
||||
&key->group.addr6.s6_addr[0x0],
|
||||
&key->group_mask.addr6.s6_addr[0x0], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
|
||||
&key->group.addr6.s6_addr[0x4],
|
||||
&key->group_mask.addr6.s6_addr[0x4], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
|
||||
&key->group.addr6.s6_addr[0x8],
|
||||
&key->group_mask.addr6.s6_addr[0x8], 4);
|
||||
mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
|
||||
&key->group.addr6.s6_addr[0xc],
|
||||
&key->group_mask.addr6.s6_addr[0xc], 4);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
|
||||
struct mlxsw_sp_mr_route_key *key,
|
||||
unsigned int priority)
|
||||
{
|
||||
struct mlxsw_sp_acl_rule_info *rulei;
|
||||
|
||||
rulei = mlxsw_sp_acl_rule_rulei(rule);
|
||||
rulei->priority = priority;
|
||||
mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
|
||||
key->vrid, GENMASK(7, 0));
|
||||
mlxsw_sp_acl_rulei_keymask_u32(rulei,
|
||||
MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
|
||||
key->vrid >> 8, GENMASK(2, 0));
|
||||
switch (key->proto) {
|
||||
case MLXSW_SP_L3_PROTO_IPV4:
|
||||
return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
|
||||
case MLXSW_SP_L3_PROTO_IPV6:
|
||||
return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
|
||||
void *route_priv,
|
||||
@ -14,7 +209,33 @@ mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
|
||||
struct mlxsw_afa_block *afa_block,
|
||||
enum mlxsw_sp_mr_route_prio prio)
|
||||
{
|
||||
struct mlxsw_sp2_mr_route *mr_route = route_priv;
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
|
||||
struct mlxsw_sp_acl_ruleset *ruleset;
|
||||
struct mlxsw_sp_acl_rule *rule;
|
||||
int err;
|
||||
|
||||
mr_route->mr_tcam = mr_tcam;
|
||||
ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
|
||||
if (WARN_ON(!ruleset))
|
||||
return -EINVAL;
|
||||
|
||||
rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
|
||||
(unsigned long) route_priv, afa_block,
|
||||
NULL);
|
||||
if (IS_ERR(rule))
|
||||
return PTR_ERR(rule);
|
||||
|
||||
mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
|
||||
err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
|
||||
if (err)
|
||||
goto err_rule_add;
|
||||
|
||||
return 0;
|
||||
|
||||
err_rule_add:
|
||||
mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -22,6 +243,21 @@ mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
|
||||
void *route_priv,
|
||||
struct mlxsw_sp_mr_route_key *key)
|
||||
{
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
|
||||
struct mlxsw_sp_acl_ruleset *ruleset;
|
||||
struct mlxsw_sp_acl_rule *rule;
|
||||
|
||||
ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
|
||||
if (WARN_ON(!ruleset))
|
||||
return;
|
||||
|
||||
rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
|
||||
(unsigned long) route_priv);
|
||||
if (WARN_ON(!rule))
|
||||
return;
|
||||
|
||||
mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
|
||||
mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -30,21 +266,64 @@ mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_mr_route_key *key,
|
||||
struct mlxsw_afa_block *afa_block)
|
||||
{
|
||||
return 0;
|
||||
struct mlxsw_sp2_mr_route *mr_route = route_priv;
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
|
||||
struct mlxsw_sp_acl_ruleset *ruleset;
|
||||
struct mlxsw_sp_acl_rule *rule;
|
||||
|
||||
ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
|
||||
if (WARN_ON(!ruleset))
|
||||
return -EINVAL;
|
||||
|
||||
rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
|
||||
(unsigned long) route_priv);
|
||||
if (WARN_ON(!rule))
|
||||
return -EINVAL;
|
||||
|
||||
return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
|
||||
}
|
||||
|
||||
static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
|
||||
{
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
|
||||
int err;
|
||||
|
||||
mr_tcam->mlxsw_sp = mlxsw_sp;
|
||||
mr_tcam->acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, NULL);
|
||||
if (!mr_tcam->acl_block)
|
||||
return -ENOMEM;
|
||||
|
||||
err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
|
||||
if (err)
|
||||
goto err_ipv4_init;
|
||||
|
||||
err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
|
||||
if (err)
|
||||
goto err_ipv6_init;
|
||||
|
||||
return 0;
|
||||
|
||||
err_ipv6_init:
|
||||
mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
|
||||
err_ipv4_init:
|
||||
mlxsw_sp_acl_block_destroy(mr_tcam->acl_block);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp2_mr_tcam_fini(void *priv)
|
||||
{
|
||||
struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
|
||||
|
||||
mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
|
||||
mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
|
||||
mlxsw_sp_acl_block_destroy(mr_tcam->acl_block);
|
||||
}
|
||||
|
||||
const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
|
||||
.priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
|
||||
.init = mlxsw_sp2_mr_tcam_init,
|
||||
.fini = mlxsw_sp2_mr_tcam_fini,
|
||||
.route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
|
||||
.route_create = mlxsw_sp2_mr_tcam_route_create,
|
||||
.route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
|
||||
.route_update = mlxsw_sp2_mr_tcam_route_update,
|
||||
|
@ -435,7 +435,8 @@ u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset)
|
||||
}
|
||||
|
||||
struct mlxsw_sp_acl_rule_info *
|
||||
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl)
|
||||
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
|
||||
struct mlxsw_afa_block *afa_block)
|
||||
{
|
||||
struct mlxsw_sp_acl_rule_info *rulei;
|
||||
int err;
|
||||
@ -443,11 +444,18 @@ mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl)
|
||||
rulei = kzalloc(sizeof(*rulei), GFP_KERNEL);
|
||||
if (!rulei)
|
||||
return NULL;
|
||||
|
||||
if (afa_block) {
|
||||
rulei->act_block = afa_block;
|
||||
return rulei;
|
||||
}
|
||||
|
||||
rulei->act_block = mlxsw_afa_block_create(acl->mlxsw_sp->afa);
|
||||
if (IS_ERR(rulei->act_block)) {
|
||||
err = PTR_ERR(rulei->act_block);
|
||||
goto err_afa_block_create;
|
||||
}
|
||||
rulei->action_created = 1;
|
||||
return rulei;
|
||||
|
||||
err_afa_block_create:
|
||||
@ -457,7 +465,8 @@ mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl)
|
||||
|
||||
void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
mlxsw_afa_block_destroy(rulei->act_block);
|
||||
if (rulei->action_created)
|
||||
mlxsw_afa_block_destroy(rulei->act_block);
|
||||
kfree(rulei);
|
||||
}
|
||||
|
||||
@ -623,6 +632,7 @@ struct mlxsw_sp_acl_rule *
|
||||
mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ruleset *ruleset,
|
||||
unsigned long cookie,
|
||||
struct mlxsw_afa_block *afa_block,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
|
||||
@ -639,7 +649,7 @@ mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
|
||||
rule->cookie = cookie;
|
||||
rule->ruleset = ruleset;
|
||||
|
||||
rule->rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl);
|
||||
rule->rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, afa_block);
|
||||
if (IS_ERR(rule->rulei)) {
|
||||
err = PTR_ERR(rule->rulei);
|
||||
goto err_rulei_create;
|
||||
@ -721,6 +731,21 @@ void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp,
|
||||
ops->rule_del(mlxsw_sp, rule->priv);
|
||||
}
|
||||
|
||||
int mlxsw_sp_acl_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_rule *rule,
|
||||
struct mlxsw_afa_block *afa_block)
|
||||
{
|
||||
struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
|
||||
const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
|
||||
struct mlxsw_sp_acl_rule_info *rulei;
|
||||
|
||||
rulei = mlxsw_sp_acl_rule_rulei(rule);
|
||||
rulei->act_block = afa_block;
|
||||
|
||||
return ops->rule_action_replace(mlxsw_sp, ruleset->priv, rule->priv,
|
||||
rule->rulei);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_acl_rule *
|
||||
mlxsw_sp_acl_rule_lookup(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ruleset *ruleset,
|
||||
|
@ -437,6 +437,34 @@ mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
|
||||
aregion->ops->lkey_id_put(aregion, lkey_id);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_atcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_entry *aentry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
|
||||
u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
|
||||
struct mlxsw_sp_acl_tcam_region *region = aregion->region;
|
||||
char ptce3_pl[MLXSW_REG_PTCE3_LEN];
|
||||
u32 kvdl_index, priority;
|
||||
int err;
|
||||
|
||||
err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
|
||||
if (err)
|
||||
return err;
|
||||
kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
|
||||
mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE,
|
||||
priority, region->tcam_region_info,
|
||||
aentry->ht_key.enc_key, erp_id,
|
||||
aentry->delta_info.start,
|
||||
aentry->delta_info.mask,
|
||||
aentry->delta_info.value,
|
||||
refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
|
||||
kvdl_index);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
|
||||
}
|
||||
|
||||
static int
|
||||
__mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
@ -506,6 +534,16 @@ __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
|
||||
}
|
||||
|
||||
static int
|
||||
__mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_entry *aentry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp, aregion,
|
||||
aentry, rulei);
|
||||
}
|
||||
|
||||
int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_chunk *achunk,
|
||||
@ -542,6 +580,29 @@ void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
__mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry);
|
||||
}
|
||||
|
||||
int
|
||||
mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_chunk *achunk,
|
||||
struct mlxsw_sp_acl_atcam_entry *aentry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mlxsw_sp_acl_atcam_is_centry(aentry))
|
||||
err = mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp,
|
||||
&aregion->cregion,
|
||||
&achunk->cchunk,
|
||||
&aentry->centry,
|
||||
rulei);
|
||||
else
|
||||
err = __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp,
|
||||
aregion, aentry,
|
||||
rulei);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam *atcam)
|
||||
{
|
||||
|
@ -89,6 +89,27 @@ mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
|
||||
cregion->ops->entry_remove(cregion, centry);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_ctcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ctcam_region *cregion,
|
||||
struct mlxsw_sp_acl_ctcam_entry *centry,
|
||||
struct mlxsw_afa_block *afa_block,
|
||||
unsigned int priority)
|
||||
{
|
||||
char ptce2_pl[MLXSW_REG_PTCE2_LEN];
|
||||
char *act_set;
|
||||
|
||||
mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_UPDATE,
|
||||
cregion->region->tcam_region_info,
|
||||
centry->parman_item.index, priority);
|
||||
|
||||
act_set = mlxsw_afa_block_first_set(afa_block);
|
||||
mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);
|
||||
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
|
||||
}
|
||||
|
||||
|
||||
static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv,
|
||||
unsigned long new_count)
|
||||
{
|
||||
@ -191,3 +212,15 @@ void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
parman_item_remove(cregion->parman, &cchunk->parman_prio,
|
||||
¢ry->parman_item);
|
||||
}
|
||||
|
||||
int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ctcam_region *cregion,
|
||||
struct mlxsw_sp_acl_ctcam_chunk *cchunk,
|
||||
struct mlxsw_sp_acl_ctcam_entry *centry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
return mlxsw_sp_acl_ctcam_region_entry_action_replace(mlxsw_sp, cregion,
|
||||
centry,
|
||||
rulei->act_block,
|
||||
rulei->priority);
|
||||
}
|
||||
|
@ -167,6 +167,11 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = {
|
||||
MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8),
|
||||
};
|
||||
|
||||
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4[] = {
|
||||
MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_7, 0x04, 24, 8),
|
||||
MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_8_10, 0x00, 0, 3),
|
||||
};
|
||||
|
||||
static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = {
|
||||
MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4),
|
||||
};
|
||||
@ -210,6 +215,7 @@ static const struct mlxsw_afk_block mlxsw_sp2_afk_blocks[] = {
|
||||
MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0),
|
||||
MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1),
|
||||
MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2),
|
||||
MLXSW_AFK_BLOCK(0x3C, mlxsw_sp_afk_element_info_ipv4_4),
|
||||
MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0),
|
||||
MLXSW_AFK_BLOCK(0x41, mlxsw_sp_afk_element_info_ipv6_1),
|
||||
MLXSW_AFK_BLOCK(0x42, mlxsw_sp_afk_element_info_ipv6_2),
|
||||
|
@ -95,8 +95,9 @@ int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
|
||||
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, KVD_SIZE))
|
||||
return -EIO;
|
||||
|
||||
max_priority = MLXSW_CORE_RES_GET(mlxsw_sp->core, KVD_SIZE);
|
||||
if (rulei->priority > max_priority)
|
||||
/* Priority range is 1..cap_kvd_size-1. */
|
||||
max_priority = MLXSW_CORE_RES_GET(mlxsw_sp->core, KVD_SIZE) - 1;
|
||||
if (rulei->priority >= max_priority)
|
||||
return -EINVAL;
|
||||
|
||||
/* Unlike in TC, in HW, higher number means higher priority. */
|
||||
@ -778,6 +779,20 @@ static void mlxsw_sp_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
mlxsw_sp_acl_tcam_chunk_put(mlxsw_sp, chunk);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_group *group,
|
||||
struct mlxsw_sp_acl_tcam_entry *entry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
|
||||
struct mlxsw_sp_acl_tcam_chunk *chunk = entry->chunk;
|
||||
struct mlxsw_sp_acl_tcam_region *region = chunk->region;
|
||||
|
||||
return ops->entry_action_replace(mlxsw_sp, region->priv, chunk->priv,
|
||||
entry->priv, rulei);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_entry *entry,
|
||||
@ -848,6 +863,15 @@ struct mlxsw_sp_acl_tcam_flower_rule {
|
||||
struct mlxsw_sp_acl_tcam_entry entry;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset {
|
||||
struct mlxsw_sp_acl_tcam_chunk *chunk;
|
||||
struct mlxsw_sp_acl_tcam_group group;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_acl_tcam_mr_rule {
|
||||
struct mlxsw_sp_acl_tcam_entry entry;
|
||||
};
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_flower_ruleset_add(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam *tcam,
|
||||
@ -929,6 +953,15 @@ mlxsw_sp_acl_tcam_flower_rule_del(struct mlxsw_sp *mlxsw_sp, void *rule_priv)
|
||||
mlxsw_sp_acl_tcam_entry_del(mlxsw_sp, &rule->entry);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_flower_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
void *ruleset_priv,
|
||||
void *rule_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_flower_rule_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
void *rule_priv, bool *activity)
|
||||
@ -949,12 +982,146 @@ static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_flower_ops = {
|
||||
.rule_priv_size = mlxsw_sp_acl_tcam_flower_rule_priv_size,
|
||||
.rule_add = mlxsw_sp_acl_tcam_flower_rule_add,
|
||||
.rule_del = mlxsw_sp_acl_tcam_flower_rule_del,
|
||||
.rule_action_replace = mlxsw_sp_acl_tcam_flower_rule_action_replace,
|
||||
.rule_activity_get = mlxsw_sp_acl_tcam_flower_rule_activity_get,
|
||||
};
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam *tcam,
|
||||
void *ruleset_priv,
|
||||
struct mlxsw_afk_element_usage *tmplt_elusage)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
|
||||
int err;
|
||||
|
||||
err = mlxsw_sp_acl_tcam_group_add(mlxsw_sp, tcam, &ruleset->group,
|
||||
mlxsw_sp_acl_tcam_patterns,
|
||||
MLXSW_SP_ACL_TCAM_PATTERNS_COUNT,
|
||||
tmplt_elusage);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* For most of the TCAM clients it would make sense to take a tcam chunk
|
||||
* only when the first rule is written. This is not the case for
|
||||
* multicast router as it is required to bind the multicast router to a
|
||||
* specific ACL Group ID which must exist in HW before multicast router
|
||||
* is initialized.
|
||||
*/
|
||||
ruleset->chunk = mlxsw_sp_acl_tcam_chunk_get(mlxsw_sp, &ruleset->group,
|
||||
1, tmplt_elusage);
|
||||
if (IS_ERR(ruleset->chunk)) {
|
||||
err = PTR_ERR(ruleset->chunk);
|
||||
goto err_chunk_get;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_chunk_get:
|
||||
mlxsw_sp_acl_tcam_group_del(mlxsw_sp, &ruleset->group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_acl_tcam_mr_ruleset_del(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
|
||||
|
||||
mlxsw_sp_acl_tcam_chunk_put(mlxsw_sp, ruleset->chunk);
|
||||
mlxsw_sp_acl_tcam_group_del(mlxsw_sp, &ruleset->group);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_mr_ruleset_bind(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
|
||||
struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
bool ingress)
|
||||
{
|
||||
/* Binding is done when initializing multicast router */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_acl_tcam_mr_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
|
||||
void *ruleset_priv,
|
||||
struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
bool ingress)
|
||||
{
|
||||
}
|
||||
|
||||
static u16
|
||||
mlxsw_sp_acl_tcam_mr_ruleset_group_id(void *ruleset_priv)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
|
||||
|
||||
return mlxsw_sp_acl_tcam_group_id(&ruleset->group);
|
||||
}
|
||||
|
||||
static size_t mlxsw_sp_acl_tcam_mr_rule_priv_size(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
return sizeof(struct mlxsw_sp_acl_tcam_mr_rule) +
|
||||
mlxsw_sp_acl_tcam_entry_priv_size(mlxsw_sp);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_mr_rule_add(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
|
||||
void *rule_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
|
||||
struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
|
||||
|
||||
return mlxsw_sp_acl_tcam_entry_add(mlxsw_sp, &ruleset->group,
|
||||
&rule->entry, rulei);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_acl_tcam_mr_rule_del(struct mlxsw_sp *mlxsw_sp, void *rule_priv)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
|
||||
|
||||
mlxsw_sp_acl_tcam_entry_del(mlxsw_sp, &rule->entry);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_mr_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
void *ruleset_priv, void *rule_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
|
||||
struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
|
||||
|
||||
return mlxsw_sp_acl_tcam_entry_action_replace(mlxsw_sp, &ruleset->group,
|
||||
&rule->entry, rulei);
|
||||
}
|
||||
|
||||
static int
|
||||
mlxsw_sp_acl_tcam_mr_rule_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
void *rule_priv, bool *activity)
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
|
||||
|
||||
return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, &rule->entry,
|
||||
activity);
|
||||
}
|
||||
|
||||
static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_mr_ops = {
|
||||
.ruleset_priv_size = sizeof(struct mlxsw_sp_acl_tcam_mr_ruleset),
|
||||
.ruleset_add = mlxsw_sp_acl_tcam_mr_ruleset_add,
|
||||
.ruleset_del = mlxsw_sp_acl_tcam_mr_ruleset_del,
|
||||
.ruleset_bind = mlxsw_sp_acl_tcam_mr_ruleset_bind,
|
||||
.ruleset_unbind = mlxsw_sp_acl_tcam_mr_ruleset_unbind,
|
||||
.ruleset_group_id = mlxsw_sp_acl_tcam_mr_ruleset_group_id,
|
||||
.rule_priv_size = mlxsw_sp_acl_tcam_mr_rule_priv_size,
|
||||
.rule_add = mlxsw_sp_acl_tcam_mr_rule_add,
|
||||
.rule_del = mlxsw_sp_acl_tcam_mr_rule_del,
|
||||
.rule_action_replace = mlxsw_sp_acl_tcam_mr_rule_action_replace,
|
||||
.rule_activity_get = mlxsw_sp_acl_tcam_mr_rule_activity_get,
|
||||
};
|
||||
|
||||
static const struct mlxsw_sp_acl_profile_ops *
|
||||
mlxsw_sp_acl_tcam_profile_ops_arr[] = {
|
||||
[MLXSW_SP_ACL_PROFILE_FLOWER] = &mlxsw_sp_acl_tcam_flower_ops,
|
||||
[MLXSW_SP_ACL_PROFILE_MR] = &mlxsw_sp_acl_tcam_mr_ops,
|
||||
};
|
||||
|
||||
const struct mlxsw_sp_acl_profile_ops *
|
||||
|
@ -48,6 +48,9 @@ struct mlxsw_sp_acl_profile_ops {
|
||||
void *ruleset_priv, void *rule_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei);
|
||||
void (*rule_del)(struct mlxsw_sp *mlxsw_sp, void *rule_priv);
|
||||
int (*rule_action_replace)(struct mlxsw_sp *mlxsw_sp,
|
||||
void *ruleset_priv, void *rule_priv,
|
||||
struct mlxsw_sp_acl_rule_info *rulei);
|
||||
int (*rule_activity_get)(struct mlxsw_sp *mlxsw_sp, void *rule_priv,
|
||||
bool *activity);
|
||||
};
|
||||
@ -121,6 +124,11 @@ void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ctcam_region *cregion,
|
||||
struct mlxsw_sp_acl_ctcam_chunk *cchunk,
|
||||
struct mlxsw_sp_acl_ctcam_entry *centry);
|
||||
int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_ctcam_region *cregion,
|
||||
struct mlxsw_sp_acl_ctcam_chunk *cchunk,
|
||||
struct mlxsw_sp_acl_ctcam_entry *centry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei);
|
||||
static inline unsigned int
|
||||
mlxsw_sp_acl_ctcam_entry_offset(struct mlxsw_sp_acl_ctcam_entry *centry)
|
||||
{
|
||||
@ -212,6 +220,11 @@ void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_chunk *achunk,
|
||||
struct mlxsw_sp_acl_atcam_entry *aentry);
|
||||
int mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam_region *aregion,
|
||||
struct mlxsw_sp_acl_atcam_chunk *achunk,
|
||||
struct mlxsw_sp_acl_atcam_entry *aentry,
|
||||
struct mlxsw_sp_acl_rule_info *rulei);
|
||||
int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_atcam *atcam);
|
||||
void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
|
||||
|
@ -406,7 +406,7 @@ int mlxsw_sp_flower_replace(struct mlxsw_sp *mlxsw_sp,
|
||||
if (IS_ERR(ruleset))
|
||||
return PTR_ERR(ruleset);
|
||||
|
||||
rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset, f->cookie,
|
||||
rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset, f->cookie, NULL,
|
||||
f->common.extack);
|
||||
if (IS_ERR(rule)) {
|
||||
err = PTR_ERR(rule);
|
||||
|
@ -15,6 +15,8 @@ PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
|
||||
PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
|
||||
NETIF_TYPE=${NETIF_TYPE:=veth}
|
||||
NETIF_CREATE=${NETIF_CREATE:=yes}
|
||||
MCD=${MCD:=smcrouted}
|
||||
MC_CLI=${MC_CLI:=smcroutectl}
|
||||
|
||||
relative_path="${BASH_SOURCE%/*}"
|
||||
if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
|
||||
|
311
tools/testing/selftests/net/forwarding/router_multicast.sh
Executable file
311
tools/testing/selftests/net/forwarding/router_multicast.sh
Executable file
@ -0,0 +1,311 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# +------------------+
|
||||
# | H1 (v$h1) |
|
||||
# | 2001:db8:1::2/64 |
|
||||
# | 198.51.100.2/28 |
|
||||
# | $h1 + |
|
||||
# +-------------|----+
|
||||
# |
|
||||
# +-------------|-------------------------------+
|
||||
# | SW1 | |
|
||||
# | $rp1 + |
|
||||
# | 198.51.100.1/28 |
|
||||
# | 2001:db8:1::1/64 |
|
||||
# | |
|
||||
# | 2001:db8:2::1/64 2001:db8:3::1/64 |
|
||||
# | 198.51.100.17/28 198.51.100.33/28 |
|
||||
# | $rp2 + $rp3 + |
|
||||
# +--------------|--------------------------|---+
|
||||
# | |
|
||||
# | |
|
||||
# +--------------|---+ +--------------|---+
|
||||
# | H2 (v$h2) | | | H3 (v$h3) | |
|
||||
# | $h2 + | | $h3 + |
|
||||
# | 198.51.100.18/28 | | 198.51.100.34/28 |
|
||||
# | 2001:db8:2::2/64 | | 2001:db8:3::2/64 |
|
||||
# +------------------+ +------------------+
|
||||
#
|
||||
|
||||
ALL_TESTS="mcast_v4 mcast_v6"
|
||||
NUM_NETIFS=6
|
||||
source lib.sh
|
||||
source tc_common.sh
|
||||
|
||||
require_command $MCD
|
||||
require_command $MC_CLI
|
||||
table_name=selftests
|
||||
|
||||
h1_create()
|
||||
{
|
||||
simple_if_init $h1 198.51.100.2/28 2001:db8:1::2/64
|
||||
|
||||
ip route add 198.51.100.16/28 vrf v$h1 nexthop via 198.51.100.1
|
||||
ip route add 198.51.100.32/28 vrf v$h1 nexthop via 198.51.100.1
|
||||
|
||||
ip route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::1
|
||||
ip route add 2001:db8:3::/64 vrf v$h1 nexthop via 2001:db8:1::1
|
||||
}
|
||||
|
||||
h1_destroy()
|
||||
{
|
||||
ip route del 2001:db8:3::/64 vrf v$h1
|
||||
ip route del 2001:db8:2::/64 vrf v$h1
|
||||
|
||||
ip route del 198.51.100.32/28 vrf v$h1
|
||||
ip route del 198.51.100.16/28 vrf v$h1
|
||||
|
||||
simple_if_fini $h1 198.51.100.2/28 2001:db8:1::2/64
|
||||
}
|
||||
|
||||
h2_create()
|
||||
{
|
||||
simple_if_init $h2 198.51.100.18/28 2001:db8:2::2/64
|
||||
|
||||
ip route add 198.51.100.0/28 vrf v$h2 nexthop via 198.51.100.17
|
||||
ip route add 198.51.100.32/28 vrf v$h2 nexthop via 198.51.100.17
|
||||
|
||||
ip route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
|
||||
ip route add 2001:db8:3::/64 vrf v$h2 nexthop via 2001:db8:2::1
|
||||
|
||||
tc qdisc add dev $h2 ingress
|
||||
}
|
||||
|
||||
h2_destroy()
|
||||
{
|
||||
tc qdisc del dev $h2 ingress
|
||||
|
||||
ip route del 2001:db8:3::/64 vrf v$h2
|
||||
ip route del 2001:db8:1::/64 vrf v$h2
|
||||
|
||||
ip route del 198.51.100.32/28 vrf v$h2
|
||||
ip route del 198.51.100.0/28 vrf v$h2
|
||||
|
||||
simple_if_fini $h2 198.51.100.18/28 2001:db8:2::2/64
|
||||
}
|
||||
|
||||
h3_create()
|
||||
{
|
||||
simple_if_init $h3 198.51.100.34/28 2001:db8:3::2/64
|
||||
|
||||
ip route add 198.51.100.0/28 vrf v$h3 nexthop via 198.51.100.33
|
||||
ip route add 198.51.100.16/28 vrf v$h3 nexthop via 198.51.100.33
|
||||
|
||||
ip route add 2001:db8:1::/64 vrf v$h3 nexthop via 2001:db8:3::1
|
||||
ip route add 2001:db8:2::/64 vrf v$h3 nexthop via 2001:db8:3::1
|
||||
|
||||
tc qdisc add dev $h3 ingress
|
||||
}
|
||||
|
||||
h3_destroy()
|
||||
{
|
||||
tc qdisc del dev $h3 ingress
|
||||
|
||||
ip route del 2001:db8:2::/64 vrf v$h3
|
||||
ip route del 2001:db8:1::/64 vrf v$h3
|
||||
|
||||
ip route del 198.51.100.16/28 vrf v$h3
|
||||
ip route del 198.51.100.0/28 vrf v$h3
|
||||
|
||||
simple_if_fini $h3 198.51.100.34/28 2001:db8:3::2/64
|
||||
}
|
||||
|
||||
router_create()
|
||||
{
|
||||
ip link set dev $rp1 up
|
||||
ip link set dev $rp2 up
|
||||
ip link set dev $rp3 up
|
||||
|
||||
ip address add 198.51.100.1/28 dev $rp1
|
||||
ip address add 198.51.100.17/28 dev $rp2
|
||||
ip address add 198.51.100.33/28 dev $rp3
|
||||
|
||||
ip address add 2001:db8:1::1/64 dev $rp1
|
||||
ip address add 2001:db8:2::1/64 dev $rp2
|
||||
ip address add 2001:db8:3::1/64 dev $rp3
|
||||
}
|
||||
|
||||
router_destroy()
|
||||
{
|
||||
ip address del 2001:db8:3::1/64 dev $rp3
|
||||
ip address del 2001:db8:2::1/64 dev $rp2
|
||||
ip address del 2001:db8:1::1/64 dev $rp1
|
||||
|
||||
ip address del 198.51.100.33/28 dev $rp3
|
||||
ip address del 198.51.100.17/28 dev $rp2
|
||||
ip address del 198.51.100.1/28 dev $rp1
|
||||
|
||||
ip link set dev $rp3 down
|
||||
ip link set dev $rp2 down
|
||||
ip link set dev $rp1 down
|
||||
}
|
||||
|
||||
start_mcd()
|
||||
{
|
||||
SMCROUTEDIR="$(mktemp -d)"
|
||||
|
||||
for ((i = 1; i <= $NUM_NETIFS; ++i)); do
|
||||
echo "phyint ${NETIFS[p$i]} enable" >> \
|
||||
$SMCROUTEDIR/$table_name.conf
|
||||
done
|
||||
|
||||
$MCD -N -I $table_name -f $SMCROUTEDIR/$table_name.conf \
|
||||
-P $SMCROUTEDIR/$table_name.pid
|
||||
}
|
||||
|
||||
kill_mcd()
|
||||
{
|
||||
pkill $MCD
|
||||
rm -rf $SMCROUTEDIR
|
||||
}
|
||||
|
||||
setup_prepare()
|
||||
{
|
||||
h1=${NETIFS[p1]}
|
||||
rp1=${NETIFS[p2]}
|
||||
|
||||
rp2=${NETIFS[p3]}
|
||||
h2=${NETIFS[p4]}
|
||||
|
||||
rp3=${NETIFS[p5]}
|
||||
h3=${NETIFS[p6]}
|
||||
|
||||
start_mcd
|
||||
|
||||
vrf_prepare
|
||||
|
||||
h1_create
|
||||
h2_create
|
||||
h3_create
|
||||
|
||||
router_create
|
||||
|
||||
forwarding_enable
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
pre_cleanup
|
||||
|
||||
forwarding_restore
|
||||
|
||||
router_destroy
|
||||
|
||||
h3_destroy
|
||||
h2_destroy
|
||||
h1_destroy
|
||||
|
||||
vrf_cleanup
|
||||
|
||||
kill_mcd
|
||||
}
|
||||
|
||||
create_mcast_sg()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local s_addr=$1; shift
|
||||
local mcast=$1; shift
|
||||
local dest_ifs=${@}
|
||||
|
||||
$MC_CLI -I $table_name add $if_name $s_addr $mcast $dest_ifs
|
||||
}
|
||||
|
||||
delete_mcast_sg()
|
||||
{
|
||||
local if_name=$1; shift
|
||||
local s_addr=$1; shift
|
||||
local mcast=$1; shift
|
||||
local dest_ifs=${@}
|
||||
|
||||
$MC_CLI -I $table_name remove $if_name $s_addr $mcast $dest_ifs
|
||||
}
|
||||
|
||||
mcast_v4()
|
||||
{
|
||||
# Add two interfaces to an MC group, send a packet to the MC group and
|
||||
# verify packets are received on both. Then delete the route and verify
|
||||
# packets are no longer received.
|
||||
|
||||
RET=0
|
||||
|
||||
tc filter add dev $h2 ingress protocol ip pref 1 handle 122 flower \
|
||||
dst_ip 225.1.2.3 action drop
|
||||
tc filter add dev $h3 ingress protocol ip pref 1 handle 133 flower \
|
||||
dst_ip 225.1.2.3 action drop
|
||||
|
||||
create_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
|
||||
|
||||
# Send frames with the corresponding L2 destination address.
|
||||
$MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
|
||||
-A 198.51.100.2 -B 225.1.2.3 -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 122 5
|
||||
check_err $? "Multicast not received on first host"
|
||||
tc_check_packets "dev $h3 ingress" 133 5
|
||||
check_err $? "Multicast not received on second host"
|
||||
|
||||
delete_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3
|
||||
|
||||
$MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \
|
||||
-A 198.51.100.2 -B 225.1.2.3 -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 122 5
|
||||
check_err $? "Multicast received on host although deleted"
|
||||
tc_check_packets "dev $h3 ingress" 133 5
|
||||
check_err $? "Multicast received on second host although deleted"
|
||||
|
||||
tc filter del dev $h3 ingress protocol ip pref 1 handle 133 flower
|
||||
tc filter del dev $h2 ingress protocol ip pref 1 handle 122 flower
|
||||
|
||||
log_test "mcast IPv4"
|
||||
}
|
||||
|
||||
mcast_v6()
|
||||
{
|
||||
# Add two interfaces to an MC group, send a packet to the MC group and
|
||||
# verify packets are received on both. Then delete the route and verify
|
||||
# packets are no longer received.
|
||||
|
||||
RET=0
|
||||
|
||||
tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 122 flower \
|
||||
dst_ip ff0e::3 action drop
|
||||
tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 133 flower \
|
||||
dst_ip ff0e::3 action drop
|
||||
|
||||
create_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
|
||||
|
||||
# Send frames with the corresponding L2 destination address.
|
||||
$MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \
|
||||
-b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 122 5
|
||||
check_err $? "Multicast not received on first host"
|
||||
tc_check_packets "dev $h3 ingress" 133 5
|
||||
check_err $? "Multicast not received on second host"
|
||||
|
||||
delete_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3
|
||||
|
||||
$MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \
|
||||
-b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q
|
||||
|
||||
tc_check_packets "dev $h2 ingress" 122 5
|
||||
check_err $? "Multicast received on first host although deleted"
|
||||
tc_check_packets "dev $h3 ingress" 133 5
|
||||
check_err $? "Multicast received on second host although deleted"
|
||||
|
||||
tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 133 flower
|
||||
tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 122 flower
|
||||
|
||||
log_test "mcast IPv6"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_prepare
|
||||
setup_wait
|
||||
|
||||
tests_run
|
||||
|
||||
exit $EXIT_STATUS
|
Loading…
Reference in New Issue
Block a user