2022-11-11 13:32:38

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 0/6] 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/[email protected]/
https://lore.kernel.org/all/[email protected]/

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


Steen Hegelund (6):
net: flow_offload: add support for ARP frame matching
net: microchip: sparx5: Add support for TC flower ARP dissector
net: microchip: sparx5: Add/delete rules in sorted order
net: microchip: sparx5: Add support for IS2 VCAP rule counters
net: microchip: sparx5: Add support for TC flower filter statistics
net: microchip: sparx5: Add KUNIT test of counters and sorted rules

.../microchip/sparx5/sparx5_tc_flower.c | 144 +++++
.../microchip/sparx5/sparx5_vcap_impl.c | 76 ++-
.../net/ethernet/microchip/vcap/vcap_api.c | 233 +++++++-
.../ethernet/microchip/vcap/vcap_api_client.h | 14 +
.../ethernet/microchip/vcap/vcap_api_kunit.c | 526 ++++++++++++++++++
include/net/flow_offload.h | 6 +
net/core/flow_offload.c | 7 +
7 files changed, 990 insertions(+), 16 deletions(-)

--
2.38.1



2022-11-11 13:33:21

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 1/6] net: flow_offload: add support for ARP frame matching

This adds a new flow_rule_match_arp function that allows drivers
to be able to dissect ARP frames.

Signed-off-by: Steen Hegelund <[email protected]>
---
include/net/flow_offload.h | 6 ++++++
net/core/flow_offload.c | 7 +++++++
2 files changed, 13 insertions(+)

diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 7a60bc6d72c9..0400a0ac8a29 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -32,6 +32,10 @@ struct flow_match_vlan {
struct flow_dissector_key_vlan *key, *mask;
};

+struct flow_match_arp {
+ struct flow_dissector_key_arp *key, *mask;
+};
+
struct flow_match_ipv4_addrs {
struct flow_dissector_key_ipv4_addrs *key, *mask;
};
@@ -98,6 +102,8 @@ void flow_rule_match_vlan(const struct flow_rule *rule,
struct flow_match_vlan *out);
void flow_rule_match_cvlan(const struct flow_rule *rule,
struct flow_match_vlan *out);
+void flow_rule_match_arp(const struct flow_rule *rule,
+ struct flow_match_arp *out);
void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out);
void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index abe423fd5736..acfc1f88ea79 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -97,6 +97,13 @@ void flow_rule_match_cvlan(const struct flow_rule *rule,
}
EXPORT_SYMBOL(flow_rule_match_cvlan);

+void flow_rule_match_arp(const struct flow_rule *rule,
+ struct flow_match_arp *out)
+{
+ FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ARP, out);
+}
+EXPORT_SYMBOL(flow_rule_match_arp);
+
void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out)
{
--
2.38.1


2022-11-11 13:33:48

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 2/6] net: microchip: sparx5: Add support for TC flower ARP dissector

This add support for Sparx5 for dissecting TC ARP flower filter keys and
sets up the Sparx5 IS2 VCAP to generate the ARP keyset for ARP frames.

Signed-off-by: Steen Hegelund <[email protected]>
---
.../microchip/sparx5/sparx5_tc_flower.c | 76 +++++++++++++++++++
.../microchip/sparx5/sparx5_vcap_impl.c | 2 +-
2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
index 7b364f6b4546..b76b8fc567bb 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
@@ -26,10 +26,24 @@ struct sparx5_tc_flower_parse_usage {
*/
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;
@@ -404,6 +418,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)
{
@@ -438,6 +513,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,
};

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
index 10bc56cd0045..db73e2b19dc5 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
@@ -540,7 +540,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,
--
2.38.1


2022-11-11 13:33:52

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 5/6] net: microchip: sparx5: Add support for TC flower filter statistics

This provides flower filter packet statistics (bytes are not supported) via
the dedicated IS2 counter feature.

All rules having the same TC cookie will contribute to the packet
statistics for the filter as they are considered to be part of the same TC
flower filter.

Signed-off-by: Steen Hegelund <[email protected]>
---
.../microchip/sparx5/sparx5_tc_flower.c | 68 +++++++++++++++++++
.../net/ethernet/microchip/vcap/vcap_api.c | 25 +++++++
.../ethernet/microchip/vcap/vcap_api_client.h | 3 +
3 files changed, 96 insertions(+)

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
index b76b8fc567bb..a48baeacc1d2 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c
@@ -21,6 +21,11 @@ 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
*/
@@ -605,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)
@@ -630,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) {
@@ -708,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)
{
@@ -729,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;
}
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index 9c660e718526..d12c8ec40fe2 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -1729,6 +1729,31 @@ void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
}
EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);

+/* Provide all rules via a callback interface */
+int vcap_rule_iter(struct vcap_control *vctrl,
+ int (*callback)(void *, struct vcap_rule *), void *arg)
+{
+ struct vcap_rule_internal *ri;
+ struct vcap_admin *admin;
+ int ret;
+
+ ret = vcap_api_check(vctrl);
+ if (ret)
+ return ret;
+
+ /* Iterate all rules in each VCAP instance */
+ list_for_each_entry(admin, &vctrl->list, list) {
+ list_for_each_entry(ri, &admin->rules, list) {
+ ret = callback(arg, &ri->data);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vcap_rule_iter);
+
int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
{
struct vcap_rule_internal *ri = to_intrule(rule);
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
index c2655045d6d4..654ef8fa6d62 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h
@@ -210,6 +210,9 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie);
/* Is the next chain id in the following lookup, possible in another VCAP */
bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
+/* Provide all rules via a callback interface */
+int vcap_rule_iter(struct vcap_control *vctrl,
+ int (*callback)(void *, struct vcap_rule *), void *arg);

/* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
--
2.38.1


2022-11-11 13:55:34

by Steen Hegelund

[permalink] [raw]
Subject: [PATCH net-next 3/6] net: microchip: sparx5: Add/delete rules in sorted order

This adds a sorting criteria to rule insertion and deletion.

The criteria is (in the listed order):

- Rule size (largest size first)
- User (based on an enumerated user value)
- Priority (highest priority first, aka lowest value)

When a rule is deleted the other rules may need to be moved to fill the gap
to use the available VCAP address space in the best possible way.

Signed-off-by: Steen Hegelund <[email protected]>
---
.../microchip/sparx5/sparx5_vcap_impl.c | 27 +++-
.../net/ethernet/microchip/vcap/vcap_api.c | 137 ++++++++++++++++--
2 files changed, 151 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
index db73e2b19dc5..b62c48a3fc45 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
@@ -477,7 +477,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 */
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c
index b6ab6bae28c0..62b675a37a96 100644
--- a/drivers/net/ethernet/microchip/vcap/vcap_api.c
+++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c
@@ -941,6 +941,16 @@ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
}
EXPORT_SYMBOL_GPL(vcap_val_rule);

+/* Entries are sorted with increasing values of sort_key.
+ * I.e. Lowest numerical sort_key is first in list.
+ * In order to locate largest keys first in list we negate the key size with
+ * (max_size - size).
+ */
+static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio)
+{
+ return ((max_size - size) << 24) | (user << 16) | prio;
+}
+
/* calculate the address of the next rule after this (lower address and prio) */
static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri)
{
@@ -970,17 +980,67 @@ static u32 vcap_set_rule_id(struct vcap_rule_internal *ri)
static int vcap_insert_rule(struct vcap_rule_internal *ri,
struct vcap_rule_move *move)
{
+ int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count;
+ struct vcap_rule_internal *duprule, *iter, *elem = NULL;
struct vcap_admin *admin = ri->admin;
- struct vcap_rule_internal *duprule;
+ u32 addr;
+
+ ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user,
+ ri->data.priority);
+
+ /* Insert the new rule in the list of rule based on the sort key
+ * If the rule needs to be inserted between existing rules then move
+ * these rules to make room for the new rule and update their start
+ * address.
+ */
+ list_for_each_entry(iter, &admin->rules, list) {
+ if (ri->sort_key < iter->sort_key) {
+ elem = iter;
+ break;
+ }
+ }
+
+ if (!elem) {
+ ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
+ admin->last_used_addr = ri->addr;
+
+ /* Add a shallow copy of the rule to the VCAP list */
+ duprule = vcap_dup_rule(ri);
+ if (IS_ERR(duprule))
+ return PTR_ERR(duprule);
+
+ list_add_tail(&duprule->list, &admin->rules);
+ return 0;
+ }
+
+ /* Reuse the space of the current rule */
+ addr = elem->addr + elem->size;
+ ri->addr = vcap_next_rule_addr(addr, ri);
+ addr = ri->addr;

- /* Only support appending rules for now */
- ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri);
- admin->last_used_addr = ri->addr;
/* Add a shallow copy of the rule to the VCAP list */
duprule = vcap_dup_rule(ri);
if (IS_ERR(duprule))
return PTR_ERR(duprule);
- list_add_tail(&duprule->list, &admin->rules);
+
+ /* Add before the current entry */
+ list_add_tail(&duprule->list, &elem->list);
+
+ /* Update the current rule */
+ elem->addr = vcap_next_rule_addr(addr, elem);
+ addr = elem->addr;
+
+ /* Update the address in the remaining rules in the list */
+ list_for_each_entry_continue(elem, &admin->rules, list) {
+ elem->addr = vcap_next_rule_addr(addr, elem);
+ addr = elem->addr;
+ }
+
+ /* Update the move info */
+ move->addr = admin->last_used_addr;
+ move->count = ri->addr - addr;
+ move->offset = admin->last_used_addr - addr;
+ admin->last_used_addr = addr;
return 0;
}

@@ -1032,8 +1092,11 @@ struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
{
struct vcap_rule_internal *ri;
struct vcap_admin *admin;
- int maxsize;
+ int err, maxsize;

+ err = vcap_api_check(vctrl);
+ if (err)
+ return ERR_PTR(err);
if (!ndev)
return ERR_PTR(-ENODEV);
/* Get the VCAP instance */
@@ -1098,12 +1161,57 @@ void vcap_free_rule(struct vcap_rule *rule)
}
EXPORT_SYMBOL_GPL(vcap_free_rule);

+/* Return the alignment offset for a new rule address */
+static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
+{
+ return (el->addr + offset) % el->size;
+}
+
+/* Update the rule address with an offset */
+static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset)
+{
+ el->addr += offset;
+}
+
+/* Rules needs to be moved to fill the gap of the deleted rule */
+static int vcap_fill_rule_gap(struct vcap_rule_internal *ri)
+{
+ struct vcap_admin *admin = ri->admin;
+ struct vcap_rule_internal *elem;
+ struct vcap_rule_move move;
+ int gap = 0, offset = 0;
+
+ /* If the first rule is deleted: Move other rules to the top */
+ if (list_is_first(&ri->list, &admin->rules))
+ offset = admin->last_valid_addr + 1 - ri->addr - ri->size;
+
+ /* Locate gaps between odd size rules and adjust the move */
+ elem = ri;
+ list_for_each_entry_continue(elem, &admin->rules, list)
+ gap += vcap_valid_rule_move(elem, ri->size);
+
+ /* Update the address in the remaining rules in the list */
+ elem = ri;
+ list_for_each_entry_continue(elem, &admin->rules, list)
+ vcap_adjust_rule_addr(elem, ri->size + gap + offset);
+
+ /* Update the move info */
+ move.addr = admin->last_used_addr;
+ move.count = ri->addr - admin->last_used_addr - gap;
+ move.offset = -(ri->size + gap + offset);
+
+ /* Do the actual move operation */
+ vcap_move_rules(ri, &move);
+
+ return gap + offset;
+}
+
/* Delete rule in a VCAP instance */
int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
{
struct vcap_rule_internal *ri, *elem;
struct vcap_admin *admin;
- int err;
+ int gap = 0, err;

/* This will later also handle rule moving */
if (!ndev)
@@ -1116,18 +1224,23 @@ int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id)
if (!ri)
return -EINVAL;
admin = ri->admin;
+
+ if (ri->addr > admin->last_used_addr)
+ gap = vcap_fill_rule_gap(ri);
+
+ /* Delete the rule from the list of rules and the cache */
list_del(&ri->list);
+ vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap);
+ kfree(ri);

- /* delete the rule in the cache */
- vctrl->ops->init(ndev, admin, ri->addr, ri->size);
+ /* Update the last used address */
if (list_empty(&admin->rules)) {
admin->last_used_addr = admin->last_valid_addr;
} else {
- /* update the address range end marker from the last rule in the list */
- elem = list_last_entry(&admin->rules, struct vcap_rule_internal, list);
+ elem = list_last_entry(&admin->rules, struct vcap_rule_internal,
+ list);
admin->last_used_addr = elem->addr;
}
- kfree(ri);
return 0;
}
EXPORT_SYMBOL_GPL(vcap_del_rule);
--
2.38.1


2022-11-14 13:48:48

by patchwork-bot+netdevbpf

[permalink] [raw]
Subject: Re: [PATCH net-next 0/6] Add support for sorted VCAP rules in Sparx5

Hello:

This series was applied to netdev/net-next.git (master)
by David S. Miller <[email protected]>:

On Fri, 11 Nov 2022 14:05:13 +0100 you wrote:
> 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/[email protected]/
> https://lore.kernel.org/all/[email protected]/
>
> [...]

Here is the summary with links:
- [net-next,1/6] net: flow_offload: add support for ARP frame matching
https://git.kernel.org/netdev/net-next/c/70ea86a0dfed
- [net-next,2/6] net: microchip: sparx5: Add support for TC flower ARP dissector
https://git.kernel.org/netdev/net-next/c/3a344f99bb55
- [net-next,3/6] net: microchip: sparx5: Add/delete rules in sorted order
https://git.kernel.org/netdev/net-next/c/990e483981ea
- [net-next,4/6] net: microchip: sparx5: Add support for IS2 VCAP rule counters
https://git.kernel.org/netdev/net-next/c/f13230a47477
- [net-next,5/6] net: microchip: sparx5: Add support for TC flower filter statistics
https://git.kernel.org/netdev/net-next/c/40e7fe18abab
- [net-next,6/6] net: microchip: sparx5: Add KUNIT test of counters and sorted rules
https://git.kernel.org/netdev/net-next/c/dccc30cc4906

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html