Merge branch 'prestera-matchall'
Maksym Glubokiy says: ==================== net: prestera: matchall features This patch series extracts matchall rules management out of SPAN API implementation and adds 2 features on top of that: - support for egress traffic (mirred egress action) - proper rule priorities management between matchall and flower ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5b3b51a181
|
@ -4,6 +4,6 @@ prestera-objs := prestera_main.o prestera_hw.o prestera_dsa.o \
|
|||
prestera_rxtx.o prestera_devlink.o prestera_ethtool.o \
|
||||
prestera_switchdev.o prestera_acl.o prestera_flow.o \
|
||||
prestera_flower.o prestera_span.o prestera_counter.o \
|
||||
prestera_router.o prestera_router_hw.o
|
||||
prestera_router.o prestera_router_hw.o prestera_matchall.o
|
||||
|
||||
obj-$(CONFIG_PRESTERA_PCI) += prestera_pci.o
|
||||
|
|
|
@ -54,6 +54,10 @@ struct prestera_acl_ruleset {
|
|||
struct prestera_acl_ruleset_ht_key ht_key;
|
||||
struct rhashtable rule_ht;
|
||||
struct prestera_acl *acl;
|
||||
struct {
|
||||
u32 min;
|
||||
u32 max;
|
||||
} prio;
|
||||
unsigned long rule_count;
|
||||
refcount_t refcount;
|
||||
void *keymask;
|
||||
|
@ -162,6 +166,9 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
|
|||
ruleset->pcl_id = PRESTERA_ACL_PCL_ID_MAKE((u8)uid, chain_index);
|
||||
ruleset->index = uid;
|
||||
|
||||
ruleset->prio.min = UINT_MAX;
|
||||
ruleset->prio.max = 0;
|
||||
|
||||
err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
|
||||
prestera_acl_ruleset_ht_params);
|
||||
if (err)
|
||||
|
@ -365,6 +372,26 @@ prestera_acl_ruleset_block_unbind(struct prestera_acl_ruleset *ruleset,
|
|||
block->ruleset_zero = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
prestera_acl_ruleset_prio_refresh(struct prestera_acl *acl,
|
||||
struct prestera_acl_ruleset *ruleset)
|
||||
{
|
||||
struct prestera_acl_rule *rule;
|
||||
|
||||
ruleset->prio.min = UINT_MAX;
|
||||
ruleset->prio.max = 0;
|
||||
|
||||
list_for_each_entry(rule, &acl->rules, list) {
|
||||
if (ruleset->ingress != rule->ruleset->ingress)
|
||||
continue;
|
||||
if (ruleset->ht_key.chain_index != rule->chain_index)
|
||||
continue;
|
||||
|
||||
ruleset->prio.min = min(ruleset->prio.min, rule->priority);
|
||||
ruleset->prio.max = max(ruleset->prio.max, rule->priority);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, u16 pcl_id)
|
||||
{
|
||||
|
@ -389,6 +416,13 @@ u32 prestera_acl_ruleset_index_get(const struct prestera_acl_ruleset *ruleset)
|
|||
return ruleset->index;
|
||||
}
|
||||
|
||||
void prestera_acl_ruleset_prio_get(struct prestera_acl_ruleset *ruleset,
|
||||
u32 *prio_min, u32 *prio_max)
|
||||
{
|
||||
*prio_min = ruleset->prio.min;
|
||||
*prio_max = ruleset->prio.max;
|
||||
}
|
||||
|
||||
bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset)
|
||||
{
|
||||
return ruleset->offload;
|
||||
|
@ -429,6 +463,13 @@ void prestera_acl_rule_destroy(struct prestera_acl_rule *rule)
|
|||
kfree(rule);
|
||||
}
|
||||
|
||||
static void prestera_acl_ruleset_prio_update(struct prestera_acl_ruleset *ruleset,
|
||||
u32 prio)
|
||||
{
|
||||
ruleset->prio.min = min(ruleset->prio.min, prio);
|
||||
ruleset->prio.max = max(ruleset->prio.max, prio);
|
||||
}
|
||||
|
||||
int prestera_acl_rule_add(struct prestera_switch *sw,
|
||||
struct prestera_acl_rule *rule)
|
||||
{
|
||||
|
@ -468,6 +509,7 @@ int prestera_acl_rule_add(struct prestera_switch *sw,
|
|||
|
||||
list_add_tail(&rule->list, &sw->acl->rules);
|
||||
ruleset->rule_count++;
|
||||
prestera_acl_ruleset_prio_update(ruleset, rule->priority);
|
||||
return 0;
|
||||
|
||||
err_acl_block_bind:
|
||||
|
@ -492,6 +534,7 @@ void prestera_acl_rule_del(struct prestera_switch *sw,
|
|||
list_del(&rule->list);
|
||||
|
||||
prestera_acl_rule_entry_destroy(sw->acl, rule->re);
|
||||
prestera_acl_ruleset_prio_refresh(sw->acl, ruleset);
|
||||
|
||||
/* unbind block (all ports) */
|
||||
if (!ruleset->ht_key.chain_index && !ruleset->rule_count)
|
||||
|
|
|
@ -195,6 +195,8 @@ int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset,
|
|||
int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset,
|
||||
struct prestera_port *port);
|
||||
u32 prestera_acl_ruleset_index_get(const struct prestera_acl_ruleset *ruleset);
|
||||
void prestera_acl_ruleset_prio_get(struct prestera_acl_ruleset *ruleset,
|
||||
u32 *prio_min, u32 *prio_max);
|
||||
void
|
||||
prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule,
|
||||
u16 pcl_id);
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
#include "prestera.h"
|
||||
#include "prestera_acl.h"
|
||||
#include "prestera_flow.h"
|
||||
#include "prestera_span.h"
|
||||
#include "prestera_flower.h"
|
||||
#include "prestera_matchall.h"
|
||||
#include "prestera_span.h"
|
||||
|
||||
static LIST_HEAD(prestera_block_cb_list);
|
||||
|
||||
|
@ -17,9 +18,9 @@ static int prestera_flow_block_mall_cb(struct prestera_flow_block *block,
|
|||
{
|
||||
switch (f->command) {
|
||||
case TC_CLSMATCHALL_REPLACE:
|
||||
return prestera_span_replace(block, f);
|
||||
return prestera_mall_replace(block, f);
|
||||
case TC_CLSMATCHALL_DESTROY:
|
||||
prestera_span_destroy(block);
|
||||
prestera_mall_destroy(block);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -89,6 +90,9 @@ prestera_flow_block_create(struct prestera_switch *sw,
|
|||
INIT_LIST_HEAD(&block->template_list);
|
||||
block->net = net;
|
||||
block->sw = sw;
|
||||
block->mall.prio_min = UINT_MAX;
|
||||
block->mall.prio_max = 0;
|
||||
block->mall.bound = false;
|
||||
block->ingress = ingress;
|
||||
|
||||
return block;
|
||||
|
@ -263,7 +267,7 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port,
|
|||
|
||||
block = flow_block_cb_priv(block_cb);
|
||||
|
||||
prestera_span_destroy(block);
|
||||
prestera_mall_destroy(block);
|
||||
|
||||
err = prestera_flow_block_unbind(block, port);
|
||||
if (err)
|
||||
|
|
|
@ -22,6 +22,11 @@ struct prestera_flow_block {
|
|||
struct prestera_acl_ruleset *ruleset_zero;
|
||||
struct flow_block_cb *block_cb;
|
||||
struct list_head template_list;
|
||||
struct {
|
||||
u32 prio_min;
|
||||
u32 prio_max;
|
||||
bool bound;
|
||||
} mall;
|
||||
unsigned int rule_count;
|
||||
bool ingress;
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "prestera_acl.h"
|
||||
#include "prestera_flow.h"
|
||||
#include "prestera_flower.h"
|
||||
#include "prestera_matchall.h"
|
||||
|
||||
struct prestera_flower_template {
|
||||
struct prestera_acl_ruleset *ruleset;
|
||||
|
@ -360,6 +361,49 @@ static int prestera_flower_parse(struct prestera_flow_block *block,
|
|||
f->common.extack);
|
||||
}
|
||||
|
||||
static int prestera_flower_prio_check(struct prestera_flow_block *block,
|
||||
struct flow_cls_offload *f)
|
||||
{
|
||||
u32 mall_prio_min;
|
||||
u32 mall_prio_max;
|
||||
int err;
|
||||
|
||||
err = prestera_mall_prio_get(block, &mall_prio_min, &mall_prio_max);
|
||||
if (err == -ENOENT)
|
||||
/* No matchall filters installed on this chain. */
|
||||
return 0;
|
||||
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG(f->common.extack, "Failed to get matchall priorities");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (f->common.prio <= mall_prio_max && block->ingress) {
|
||||
NL_SET_ERR_MSG(f->common.extack,
|
||||
"Failed to add in front of existing matchall rules");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (f->common.prio >= mall_prio_min && !block->ingress) {
|
||||
NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing matchall rules");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prestera_flower_prio_get(struct prestera_flow_block *block, u32 chain_index,
|
||||
u32 *prio_min, u32 *prio_max)
|
||||
{
|
||||
struct prestera_acl_ruleset *ruleset;
|
||||
|
||||
ruleset = prestera_acl_ruleset_lookup(block->sw->acl, block, chain_index);
|
||||
if (IS_ERR(ruleset))
|
||||
return PTR_ERR(ruleset);
|
||||
|
||||
prestera_acl_ruleset_prio_get(ruleset, prio_min, prio_max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prestera_flower_replace(struct prestera_flow_block *block,
|
||||
struct flow_cls_offload *f)
|
||||
{
|
||||
|
@ -368,6 +412,10 @@ int prestera_flower_replace(struct prestera_flow_block *block,
|
|||
struct prestera_acl_rule *rule;
|
||||
int err;
|
||||
|
||||
err = prestera_flower_prio_check(block, f);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ruleset = prestera_acl_ruleset_get(acl, block, f->common.chain_index);
|
||||
if (IS_ERR(ruleset))
|
||||
return PTR_ERR(ruleset);
|
||||
|
|
|
@ -19,5 +19,7 @@ int prestera_flower_tmplt_create(struct prestera_flow_block *block,
|
|||
void prestera_flower_tmplt_destroy(struct prestera_flow_block *block,
|
||||
struct flow_cls_offload *f);
|
||||
void prestera_flower_template_cleanup(struct prestera_flow_block *block);
|
||||
int prestera_flower_prio_get(struct prestera_flow_block *block, u32 chain_index,
|
||||
u32 *prio_min, u32 *prio_max);
|
||||
|
||||
#endif /* _PRESTERA_FLOWER_H_ */
|
||||
|
|
|
@ -78,9 +78,11 @@ enum prestera_cmd_type_t {
|
|||
PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,
|
||||
|
||||
PRESTERA_CMD_TYPE_SPAN_GET = 0x1100,
|
||||
PRESTERA_CMD_TYPE_SPAN_BIND = 0x1101,
|
||||
PRESTERA_CMD_TYPE_SPAN_UNBIND = 0x1102,
|
||||
PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND = 0x1101,
|
||||
PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND = 0x1102,
|
||||
PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103,
|
||||
PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND = 0x1104,
|
||||
PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND = 0x1105,
|
||||
|
||||
PRESTERA_CMD_TYPE_POLICER_CREATE = 0x1500,
|
||||
PRESTERA_CMD_TYPE_POLICER_RELEASE = 0x1501,
|
||||
|
@ -1434,27 +1436,39 @@ int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id)
|
||||
int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id,
|
||||
bool ingress)
|
||||
{
|
||||
struct prestera_msg_span_req req = {
|
||||
.port = __cpu_to_le32(port->hw_id),
|
||||
.dev = __cpu_to_le32(port->dev_id),
|
||||
.id = span_id,
|
||||
};
|
||||
enum prestera_cmd_type_t cmd_type;
|
||||
|
||||
if (ingress)
|
||||
cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND;
|
||||
else
|
||||
cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND;
|
||||
|
||||
return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req));
|
||||
|
||||
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_BIND,
|
||||
&req.cmd, sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_span_unbind(const struct prestera_port *port)
|
||||
int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress)
|
||||
{
|
||||
struct prestera_msg_span_req req = {
|
||||
.port = __cpu_to_le32(port->hw_id),
|
||||
.dev = __cpu_to_le32(port->dev_id),
|
||||
};
|
||||
enum prestera_cmd_type_t cmd_type;
|
||||
|
||||
return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_SPAN_UNBIND,
|
||||
&req.cmd, sizeof(req));
|
||||
if (ingress)
|
||||
cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND;
|
||||
else
|
||||
cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND;
|
||||
|
||||
return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req));
|
||||
}
|
||||
|
||||
int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id)
|
||||
|
|
|
@ -245,8 +245,9 @@ int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id,
|
|||
|
||||
/* SPAN API */
|
||||
int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id);
|
||||
int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id);
|
||||
int prestera_hw_span_unbind(const struct prestera_port *port);
|
||||
int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id,
|
||||
bool ingress);
|
||||
int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress);
|
||||
int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id);
|
||||
|
||||
/* Router API */
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
|
||||
/* Copyright (c) 2019-2022 Marvell International Ltd. All rights reserved */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "prestera.h"
|
||||
#include "prestera_hw.h"
|
||||
#include "prestera_flow.h"
|
||||
#include "prestera_flower.h"
|
||||
#include "prestera_matchall.h"
|
||||
#include "prestera_span.h"
|
||||
|
||||
static int prestera_mall_prio_check(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f)
|
||||
{
|
||||
u32 flower_prio_min;
|
||||
u32 flower_prio_max;
|
||||
int err;
|
||||
|
||||
err = prestera_flower_prio_get(block, f->common.chain_index,
|
||||
&flower_prio_min, &flower_prio_max);
|
||||
if (err == -ENOENT)
|
||||
/* No flower filters installed on this chain. */
|
||||
return 0;
|
||||
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG(f->common.extack, "Failed to get flower priorities");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (f->common.prio <= flower_prio_max && !block->ingress) {
|
||||
NL_SET_ERR_MSG(f->common.extack, "Failed to add in front of existing flower rules");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (f->common.prio >= flower_prio_min && block->ingress) {
|
||||
NL_SET_ERR_MSG(f->common.extack, "Failed to add behind of existing flower rules");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prestera_mall_prio_get(struct prestera_flow_block *block,
|
||||
u32 *prio_min, u32 *prio_max)
|
||||
{
|
||||
if (!block->mall.bound)
|
||||
return -ENOENT;
|
||||
|
||||
*prio_min = block->mall.prio_min;
|
||||
*prio_max = block->mall.prio_max;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prestera_mall_prio_update(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f)
|
||||
{
|
||||
block->mall.prio_min = min(block->mall.prio_min, f->common.prio);
|
||||
block->mall.prio_max = max(block->mall.prio_max, f->common.prio);
|
||||
}
|
||||
|
||||
int prestera_mall_replace(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f)
|
||||
{
|
||||
struct prestera_flow_block_binding *binding;
|
||||
__be16 protocol = f->common.protocol;
|
||||
struct flow_action_entry *act;
|
||||
struct prestera_port *port;
|
||||
int err;
|
||||
|
||||
if (!flow_offload_has_one_action(&f->rule->action)) {
|
||||
NL_SET_ERR_MSG(f->common.extack,
|
||||
"Only singular actions are supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
act = &f->rule->action.entries[0];
|
||||
|
||||
if (!prestera_netdev_check(act->dev)) {
|
||||
NL_SET_ERR_MSG(f->common.extack,
|
||||
"Only Marvell Prestera port is supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!tc_cls_can_offload_and_chain0(act->dev, &f->common))
|
||||
return -EOPNOTSUPP;
|
||||
if (act->id != FLOW_ACTION_MIRRED)
|
||||
return -EOPNOTSUPP;
|
||||
if (protocol != htons(ETH_P_ALL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = prestera_mall_prio_check(block, f);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
port = netdev_priv(act->dev);
|
||||
|
||||
list_for_each_entry(binding, &block->binding_list, list) {
|
||||
err = prestera_span_rule_add(binding, port, block->ingress);
|
||||
if (err)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
prestera_mall_prio_update(block, f);
|
||||
|
||||
block->mall.bound = true;
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
list_for_each_entry_continue_reverse(binding,
|
||||
&block->binding_list, list)
|
||||
prestera_span_rule_del(binding, block->ingress);
|
||||
return err;
|
||||
}
|
||||
|
||||
void prestera_mall_destroy(struct prestera_flow_block *block)
|
||||
{
|
||||
struct prestera_flow_block_binding *binding;
|
||||
|
||||
list_for_each_entry(binding, &block->binding_list, list)
|
||||
prestera_span_rule_del(binding, block->ingress);
|
||||
|
||||
block->mall.prio_min = UINT_MAX;
|
||||
block->mall.prio_max = 0;
|
||||
block->mall.bound = false;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
|
||||
/* Copyright (c) 2022 Marvell International Ltd. All rights reserved. */
|
||||
|
||||
#ifndef _PRESTERA_MATCHALL_H_
|
||||
#define _PRESTERA_MATCHALL_H_
|
||||
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
struct prestera_flow_block;
|
||||
|
||||
int prestera_mall_replace(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f);
|
||||
void prestera_mall_destroy(struct prestera_flow_block *block);
|
||||
int prestera_mall_prio_get(struct prestera_flow_block *block,
|
||||
u32 *prio_min, u32 *prio_max);
|
||||
|
||||
#endif /* _PRESTERA_MATCHALL_H_ */
|
|
@ -120,8 +120,9 @@ static int prestera_span_put(struct prestera_switch *sw, u8 span_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
|
||||
struct prestera_port *to_port)
|
||||
int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
|
||||
struct prestera_port *to_port,
|
||||
bool ingress)
|
||||
{
|
||||
struct prestera_switch *sw = binding->port->sw;
|
||||
u8 span_id;
|
||||
|
@ -135,7 +136,7 @@ static int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = prestera_hw_span_bind(binding->port, span_id);
|
||||
err = prestera_hw_span_bind(binding->port, span_id, ingress);
|
||||
if (err) {
|
||||
prestera_span_put(sw, span_id);
|
||||
return err;
|
||||
|
@ -145,11 +146,12 @@ static int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int prestera_span_rule_del(struct prestera_flow_block_binding *binding)
|
||||
int prestera_span_rule_del(struct prestera_flow_block_binding *binding,
|
||||
bool ingress)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = prestera_hw_span_unbind(binding->port);
|
||||
err = prestera_hw_span_unbind(binding->port, ingress);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -161,60 +163,6 @@ static int prestera_span_rule_del(struct prestera_flow_block_binding *binding)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int prestera_span_replace(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f)
|
||||
{
|
||||
struct prestera_flow_block_binding *binding;
|
||||
__be16 protocol = f->common.protocol;
|
||||
struct flow_action_entry *act;
|
||||
struct prestera_port *port;
|
||||
int err;
|
||||
|
||||
if (!flow_offload_has_one_action(&f->rule->action)) {
|
||||
NL_SET_ERR_MSG(f->common.extack,
|
||||
"Only singular actions are supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
act = &f->rule->action.entries[0];
|
||||
|
||||
if (!prestera_netdev_check(act->dev)) {
|
||||
NL_SET_ERR_MSG(f->common.extack,
|
||||
"Only Marvell Prestera port is supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!tc_cls_can_offload_and_chain0(act->dev, &f->common))
|
||||
return -EOPNOTSUPP;
|
||||
if (act->id != FLOW_ACTION_MIRRED)
|
||||
return -EOPNOTSUPP;
|
||||
if (protocol != htons(ETH_P_ALL))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
port = netdev_priv(act->dev);
|
||||
|
||||
list_for_each_entry(binding, &block->binding_list, list) {
|
||||
err = prestera_span_rule_add(binding, port);
|
||||
if (err)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
list_for_each_entry_continue_reverse(binding,
|
||||
&block->binding_list, list)
|
||||
prestera_span_rule_del(binding);
|
||||
return err;
|
||||
}
|
||||
|
||||
void prestera_span_destroy(struct prestera_flow_block *block)
|
||||
{
|
||||
struct prestera_flow_block_binding *binding;
|
||||
|
||||
list_for_each_entry(binding, &block->binding_list, list)
|
||||
prestera_span_rule_del(binding);
|
||||
}
|
||||
|
||||
int prestera_span_init(struct prestera_switch *sw)
|
||||
{
|
||||
struct prestera_span *span;
|
||||
|
|
|
@ -8,13 +8,17 @@
|
|||
|
||||
#define PRESTERA_SPAN_INVALID_ID -1
|
||||
|
||||
struct prestera_port;
|
||||
struct prestera_switch;
|
||||
struct prestera_flow_block;
|
||||
struct prestera_flow_block_binding;
|
||||
|
||||
int prestera_span_init(struct prestera_switch *sw);
|
||||
void prestera_span_fini(struct prestera_switch *sw);
|
||||
int prestera_span_replace(struct prestera_flow_block *block,
|
||||
struct tc_cls_matchall_offload *f);
|
||||
void prestera_span_destroy(struct prestera_flow_block *block);
|
||||
|
||||
int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
|
||||
struct prestera_port *to_port,
|
||||
bool ingress);
|
||||
int prestera_span_rule_del(struct prestera_flow_block_binding *binding,
|
||||
bool ingress);
|
||||
|
||||
#endif /* _PRESTERA_SPAN_H_ */
|
||||
|
|
Loading…
Reference in New Issue