Skip to content

Commit

Permalink
Merge branch 'sparx5-sorted-VCAP-rules'
Browse files Browse the repository at this point in the history
Steen Hegelund says:

====================
net: Add support for sorted VCAP rules in Sparx5

This provides support for adding Sparx5 VCAP rules in sorted order, VCAP
rule counters and TC filter matching on ARP frames.

It builds on top of the initial IS2 VCAP support found in these series:

https://lore.kernel.org/all/20221020130904.1215072-1-steen.hegelund@microchip.com/
https://lore.kernel.org/all/20221109114116.3612477-1-steen.hegelund@microchip.com/

Functionality
=============

When a new VCAP rule is added the driver will now ensure that the rule is
inserted in sorted order, and when a rule is removed, the remaining rules
will be moved to keep the sorted order and remove any gaps in the VCAP
address space.

A VCAP rule is ordered using these 3 values:

 - Rule size: the count of VCAP addresses used by the rule.  The largest
   rule have highest priority

 - Rule User: The rules are ordered by the user enumeration

 - Priority: The priority provided in the flower filter.  The lowest value
   has the highest priority.

A VCAP instance may contain the counter as part of the VCAP cache area, and
this counter may be one or more bits in width.  This type of counter
automatically increments its value when the rule is hit.

Other VCAP instances have a dedicated counter area outside of the VCAP and
in this case the rule must contain the counter id to be able to locate the
counter value and cause the counter to be incremented.  In this case there
must also be a VCAP rule action that sets the counter id.

The Sparx5 IS2 VCAP uses a dedicated counter area with 32bit counters.

This series adds support for getting VCAP rule counters and provide these
via the TC statistic interface.

This only support packet counters, not byte counters.

Finally the series adds support for the ARP frame dissector and configures
the Sparx5 IS2 VCAP to generate the ARP keyset when ARP traffic is
received.

Delivery:
=========

This is current plan for delivering the full VCAP feature set of Sparx5:

- DebugFS support for inspecting rules
- TC protocol all support
- Sparx5 IS0 VCAP support
- TC policer and drop action support (depends on the Sparx5 QoS support
  upstreamed separately)
- Sparx5 ES0 VCAP support
- TC flower template support
- TC matchall filter support for mirroring and policing ports
- TC flower filter mirror action support
- Sparx5 ES2 VCAP support
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 14, 2022
2 parents 2fd450c + dccc30c commit 4d1bbdf
Show file tree
Hide file tree
Showing 7 changed files with 990 additions and 16 deletions.
144 changes: 144 additions & 0 deletions drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,34 @@ struct sparx5_tc_flower_parse_usage {
unsigned int used_keys;
};

struct sparx5_tc_rule_pkt_cnt {
u64 cookie;
u32 pkts;
};

/* These protocols have dedicated keysets in IS2 and a TC dissector
* ETH_P_ARP does not have a TC dissector
*/
static u16 sparx5_tc_known_etypes[] = {
ETH_P_ALL,
ETH_P_ARP,
ETH_P_IP,
ETH_P_IPV6,
};

enum sparx5_is2_arp_opcode {
SPX5_IS2_ARP_REQUEST,
SPX5_IS2_ARP_REPLY,
SPX5_IS2_RARP_REQUEST,
SPX5_IS2_RARP_REPLY,
};

enum tc_arp_opcode {
TC_ARP_OP_RESERVED,
TC_ARP_OP_REQUEST,
TC_ARP_OP_REPLY,
};

static bool sparx5_tc_is_known_etype(u16 etype)
{
int idx;
Expand Down Expand Up @@ -404,6 +423,67 @@ sparx5_tc_flower_handler_tcp_usage(struct sparx5_tc_flower_parse_usage *st)
return err;
}

static int
sparx5_tc_flower_handler_arp_usage(struct sparx5_tc_flower_parse_usage *st)
{
struct flow_match_arp mt;
u16 value, mask;
u32 ipval, ipmsk;
int err;

flow_rule_match_arp(st->frule, &mt);

if (mt.mask->op) {
mask = 0x3;
if (st->l3_proto == ETH_P_ARP) {
value = mt.key->op == TC_ARP_OP_REQUEST ?
SPX5_IS2_ARP_REQUEST :
SPX5_IS2_ARP_REPLY;
} else { /* RARP */
value = mt.key->op == TC_ARP_OP_REQUEST ?
SPX5_IS2_RARP_REQUEST :
SPX5_IS2_RARP_REPLY;
}
err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ARP_OPCODE,
value, mask);
if (err)
goto out;
}

/* The IS2 ARP keyset does not support ARP hardware addresses */
if (!is_zero_ether_addr(mt.mask->sha) ||
!is_zero_ether_addr(mt.mask->tha))
goto out;

if (mt.mask->sip) {
ipval = be32_to_cpu((__force __be32)mt.key->sip);
ipmsk = be32_to_cpu((__force __be32)mt.mask->sip);

err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_SIP,
ipval, ipmsk);
if (err)
goto out;
}

if (mt.mask->tip) {
ipval = be32_to_cpu((__force __be32)mt.key->tip);
ipmsk = be32_to_cpu((__force __be32)mt.mask->tip);

err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_IP4_DIP,
ipval, ipmsk);
if (err)
goto out;
}

st->used_keys |= BIT(FLOW_DISSECTOR_KEY_ARP);

return err;

out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
return err;
}

static int
sparx5_tc_flower_handler_ip_usage(struct sparx5_tc_flower_parse_usage *st)
{
Expand Down Expand Up @@ -438,6 +518,7 @@ static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_us
[FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
[FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
[FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage,
[FLOW_DISSECTOR_KEY_ARP] = sparx5_tc_flower_handler_arp_usage,
[FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage,
};

Expand Down Expand Up @@ -529,6 +610,20 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
return 0;
}

/* Add a rule counter action - only IS2 is considered for now */
static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
struct vcap_rule *vrule)
{
int err;

err = vcap_rule_add_action_u32(vrule, VCAP_AF_CNT_ID, vrule->id);
if (err)
return err;

vcap_rule_set_counter_id(vrule, vrule->id);
return err;
}

static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
Expand All @@ -554,6 +649,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,

vrule->cookie = fco->cookie;
sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);

err = sparx5_tc_add_rule_counter(admin, vrule);
if (err)
goto out;

frule = flow_cls_offload_flow_rule(fco);
flow_action_for_each(idx, act, &frule->action) {
switch (act->id) {
Expand Down Expand Up @@ -632,6 +732,48 @@ static int sparx5_tc_flower_destroy(struct net_device *ndev,
return err;
}

/* Collect packet counts from all rules with the same cookie */
static int sparx5_tc_rule_counter_cb(void *arg, struct vcap_rule *rule)
{
struct sparx5_tc_rule_pkt_cnt *rinfo = arg;
struct vcap_counter counter;
int err = 0;

if (rule->cookie == rinfo->cookie) {
err = vcap_rule_get_counter(rule, &counter);
if (err)
return err;
rinfo->pkts += counter.value;
/* Reset the rule counter */
counter.value = 0;
vcap_rule_set_counter(rule, &counter);
}
return err;
}

static int sparx5_tc_flower_stats(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5_tc_rule_pkt_cnt rinfo = {};
struct vcap_control *vctrl;
ulong lastused = 0;
u64 drops = 0;
u32 pkts = 0;
int err;

rinfo.cookie = fco->cookie;
vctrl = port->sparx5->vcap_ctrl;
err = vcap_rule_iter(vctrl, sparx5_tc_rule_counter_cb, &rinfo);
if (err)
return err;
pkts = rinfo.pkts;
flow_stats_update(&fco->stats, 0x0, pkts, drops, lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
return err;
}

int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress)
{
Expand All @@ -653,6 +795,8 @@ int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
return sparx5_tc_flower_replace(ndev, fco, admin);
case FLOW_CLS_DESTROY:
return sparx5_tc_flower_destroy(ndev, fco, admin);
case FLOW_CLS_STATS:
return sparx5_tc_flower_stats(ndev, fco, admin);
default:
return -EOPNOTSUPP;
}
Expand Down
76 changes: 72 additions & 4 deletions drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,58 @@ static void sparx5_vcap_cache_write(struct net_device *ndev,
default:
break;
}
if (sel & VCAP_SEL_COUNTER) {
start = start & 0xfff; /* counter limit */
if (admin->vinst == 0)
spx5_wr(admin->cache.counter, sparx5,
ANA_ACL_CNT_A(start));
else
spx5_wr(admin->cache.counter, sparx5,
ANA_ACL_CNT_B(start));
spx5_wr(admin->cache.sticky, sparx5,
VCAP_SUPER_VCAP_CNT_DAT(0));
}
}

/* API callback used for reading from the VCAP into the VCAP cache */
static void sparx5_vcap_cache_read(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel, u32 start,
enum vcap_selection sel,
u32 start,
u32 count)
{
/* this will be added later */
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
u32 *keystr, *mskstr, *actstr;
int idx;

keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
actstr = &admin->cache.actionstream[start];
if (sel & VCAP_SEL_ENTRY) {
for (idx = 0; idx < count; ++idx) {
keystr[idx] = spx5_rd(sparx5,
VCAP_SUPER_VCAP_ENTRY_DAT(idx));
mskstr[idx] = ~spx5_rd(sparx5,
VCAP_SUPER_VCAP_MASK_DAT(idx));
}
}
if (sel & VCAP_SEL_ACTION) {
for (idx = 0; idx < count; ++idx)
actstr[idx] = spx5_rd(sparx5,
VCAP_SUPER_VCAP_ACTION_DAT(idx));
}
if (sel & VCAP_SEL_COUNTER) {
start = start & 0xfff; /* counter limit */
if (admin->vinst == 0)
admin->cache.counter =
spx5_rd(sparx5, ANA_ACL_CNT_A(start));
else
admin->cache.counter =
spx5_rd(sparx5, ANA_ACL_CNT_B(start));
admin->cache.sticky =
spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));
}
}

/* API callback used for initializing a VCAP address range */
Expand Down Expand Up @@ -477,7 +520,32 @@ static void sparx5_vcap_update(struct net_device *ndev,
static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
u32 addr, int offset, int count)
{
/* this will be added later */
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
enum vcap_command cmd;
u16 mv_num_pos;
u16 mv_size;

mv_size = count - 1;
if (offset > 0) {
mv_num_pos = offset - 1;
cmd = VCAP_CMD_MOVE_DOWN;
} else {
mv_num_pos = -offset - 1;
cmd = VCAP_CMD_MOVE_UP;
}
spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(mv_num_pos) |
VCAP_SUPER_CFG_MV_SIZE_SET(mv_size),
sparx5, VCAP_SUPER_CFG);
spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |
VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |
VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
VCAP_SUPER_CTRL_CLEAR_CACHE_SET(false) |
VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
sparx5, VCAP_SUPER_CTRL);
sparx5_vcap_wait_super_update(sparx5);
}

/* Provide port information via a callback interface */
Expand Down Expand Up @@ -540,7 +608,7 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
VCAP_IS2_PS_ARP_MAC_ETYPE);
VCAP_IS2_PS_ARP_ARP);
for (lookup = 0; lookup < admin->lookups; ++lookup) {
for (portno = 0; portno < SPX5_PORTS; ++portno) {
spx5_wr(keysel, sparx5,
Expand Down
Loading

0 comments on commit 4d1bbdf

Please sign in to comment.