-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: microchip: sparx5: Adding initial tc flower support for VCAP API
This adds initial TC flower filter support to Sparx5 for the IS2 VCAP. The support consists of the source and destination MAC addresses, and the trap and pass actions. This is how you can create a rule that test the functionality: tc qdisc add dev eth0 clsact tc filter add dev eth0 ingress chain 8000000 prio 10 handle 10 \ protocol all flower skip_sw \ dst_mac 0a:0b:0c:0d:0e:0f \ src_mac 2:0:0:0:0:1 \ action trap The IS2 chains in Sparx5 are assigned like this: - chain 8000000: IS2 Lookup 0 - chain 8100000: IS2 Lookup 1 - chain 8200000: IS2 Lookup 2 - chain 8300000: IS2 Lookup 3 Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com> Tested-by: Casper Andersson <casper.casan@gmail.com> Reviewed-by: Casper Andersson <casper.casan@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Steen Hegelund
authored and
David S. Miller
committed
Oct 24, 2022
1 parent
45c00ad
commit c9da1ac
Showing
10 changed files
with
1,011 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
217 changes: 217 additions & 0 deletions
217
drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
/* Microchip VCAP API | ||
* | ||
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. | ||
*/ | ||
|
||
#include <net/tcp.h> | ||
|
||
#include "sparx5_tc.h" | ||
#include "vcap_api.h" | ||
#include "vcap_api_client.h" | ||
#include "sparx5_main.h" | ||
#include "sparx5_vcap_impl.h" | ||
|
||
struct sparx5_tc_flower_parse_usage { | ||
struct flow_cls_offload *fco; | ||
struct flow_rule *frule; | ||
struct vcap_rule *vrule; | ||
unsigned int used_keys; | ||
}; | ||
|
||
static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) | ||
{ | ||
enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; | ||
enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC; | ||
struct flow_match_eth_addrs match; | ||
struct vcap_u48_key smac, dmac; | ||
int err = 0; | ||
|
||
flow_rule_match_eth_addrs(st->frule, &match); | ||
|
||
if (!is_zero_ether_addr(match.mask->src)) { | ||
vcap_netbytes_copy(smac.value, match.key->src, ETH_ALEN); | ||
vcap_netbytes_copy(smac.mask, match.mask->src, ETH_ALEN); | ||
err = vcap_rule_add_key_u48(st->vrule, smac_key, &smac); | ||
if (err) | ||
goto out; | ||
} | ||
|
||
if (!is_zero_ether_addr(match.mask->dst)) { | ||
vcap_netbytes_copy(dmac.value, match.key->dst, ETH_ALEN); | ||
vcap_netbytes_copy(dmac.mask, match.mask->dst, ETH_ALEN); | ||
err = vcap_rule_add_key_u48(st->vrule, dmac_key, &dmac); | ||
if (err) | ||
goto out; | ||
} | ||
|
||
st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS); | ||
|
||
return err; | ||
|
||
out: | ||
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error"); | ||
return err; | ||
} | ||
|
||
static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { | ||
/* More dissector handlers will be added here later */ | ||
[FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, | ||
}; | ||
|
||
static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, | ||
struct vcap_admin *admin, | ||
struct vcap_rule *vrule) | ||
{ | ||
struct sparx5_tc_flower_parse_usage state = { | ||
.fco = fco, | ||
.vrule = vrule, | ||
}; | ||
int idx, err = 0; | ||
|
||
state.frule = flow_cls_offload_flow_rule(fco); | ||
for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { | ||
if (!flow_rule_match_key(state.frule, idx)) | ||
continue; | ||
if (!sparx5_tc_flower_usage_handlers[idx]) | ||
continue; | ||
err = sparx5_tc_flower_usage_handlers[idx](&state); | ||
if (err) | ||
return err; | ||
} | ||
return err; | ||
} | ||
|
||
static int sparx5_tc_flower_replace(struct net_device *ndev, | ||
struct flow_cls_offload *fco, | ||
struct vcap_admin *admin) | ||
{ | ||
struct sparx5_port *port = netdev_priv(ndev); | ||
struct flow_action_entry *act; | ||
struct vcap_control *vctrl; | ||
struct flow_rule *frule; | ||
struct vcap_rule *vrule; | ||
int err, idx; | ||
|
||
frule = flow_cls_offload_flow_rule(fco); | ||
if (!flow_action_has_entries(&frule->action)) { | ||
NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); | ||
return -EINVAL; | ||
} | ||
|
||
if (!flow_action_basic_hw_stats_check(&frule->action, fco->common.extack)) | ||
return -EOPNOTSUPP; | ||
|
||
vctrl = port->sparx5->vcap_ctrl; | ||
vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, | ||
fco->common.prio, 0); | ||
if (IS_ERR(vrule)) | ||
return PTR_ERR(vrule); | ||
|
||
vrule->cookie = fco->cookie; | ||
sparx5_tc_use_dissectors(fco, admin, vrule); | ||
flow_action_for_each(idx, act, &frule->action) { | ||
switch (act->id) { | ||
case FLOW_ACTION_TRAP: | ||
err = vcap_rule_add_action_bit(vrule, | ||
VCAP_AF_CPU_COPY_ENA, | ||
VCAP_BIT_1); | ||
if (err) | ||
goto out; | ||
err = vcap_rule_add_action_u32(vrule, | ||
VCAP_AF_CPU_QUEUE_NUM, 0); | ||
if (err) | ||
goto out; | ||
err = vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, | ||
SPX5_PMM_REPLACE_ALL); | ||
if (err) | ||
goto out; | ||
/* For now the actionset is hardcoded */ | ||
err = vcap_set_rule_set_actionset(vrule, | ||
VCAP_AFS_BASE_TYPE); | ||
if (err) | ||
goto out; | ||
break; | ||
case FLOW_ACTION_ACCEPT: | ||
/* For now the actionset is hardcoded */ | ||
err = vcap_set_rule_set_actionset(vrule, | ||
VCAP_AFS_BASE_TYPE); | ||
if (err) | ||
goto out; | ||
break; | ||
default: | ||
NL_SET_ERR_MSG_MOD(fco->common.extack, | ||
"Unsupported TC action"); | ||
err = -EOPNOTSUPP; | ||
goto out; | ||
} | ||
} | ||
/* For now the keyset is hardcoded */ | ||
err = vcap_set_rule_set_keyset(vrule, VCAP_KFS_MAC_ETYPE); | ||
if (err) { | ||
NL_SET_ERR_MSG_MOD(fco->common.extack, | ||
"No matching port keyset for filter protocol and keys"); | ||
goto out; | ||
} | ||
err = vcap_val_rule(vrule, ETH_P_ALL); | ||
if (err) { | ||
vcap_set_tc_exterr(fco, vrule); | ||
goto out; | ||
} | ||
err = vcap_add_rule(vrule); | ||
if (err) | ||
NL_SET_ERR_MSG_MOD(fco->common.extack, | ||
"Could not add the filter"); | ||
out: | ||
vcap_free_rule(vrule); | ||
return err; | ||
} | ||
|
||
static int sparx5_tc_flower_destroy(struct net_device *ndev, | ||
struct flow_cls_offload *fco, | ||
struct vcap_admin *admin) | ||
{ | ||
struct sparx5_port *port = netdev_priv(ndev); | ||
struct vcap_control *vctrl; | ||
int err = -ENOENT, rule_id; | ||
|
||
vctrl = port->sparx5->vcap_ctrl; | ||
while (true) { | ||
rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); | ||
if (rule_id <= 0) | ||
break; | ||
err = vcap_del_rule(vctrl, ndev, rule_id); | ||
if (err) { | ||
pr_err("%s:%d: could not delete rule %d\n", | ||
__func__, __LINE__, rule_id); | ||
break; | ||
} | ||
} | ||
return err; | ||
} | ||
|
||
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, | ||
bool ingress) | ||
{ | ||
struct sparx5_port *port = netdev_priv(ndev); | ||
struct vcap_control *vctrl; | ||
struct vcap_admin *admin; | ||
int err = -EINVAL; | ||
|
||
/* Get vcap instance from the chain id */ | ||
vctrl = port->sparx5->vcap_ctrl; | ||
admin = vcap_find_admin(vctrl, fco->common.chain_index); | ||
if (!admin) { | ||
NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); | ||
return err; | ||
} | ||
|
||
switch (fco->command) { | ||
case FLOW_CLS_REPLACE: | ||
return sparx5_tc_flower_replace(ndev, fco, admin); | ||
case FLOW_CLS_DESTROY: | ||
return sparx5_tc_flower_destroy(ndev, fco, admin); | ||
default: | ||
return -EOPNOTSUPP; | ||
} | ||
} |
Oops, something went wrong.