Commit f53e1432 authored by David S. Miller's avatar David S. Miller

Merge branch 'sparx5-TC-key'

Steen Hegelund says:

====================
Extend TC key support for Sparx5 IS2 VCAP

This provides extended tc flower filter key support for the Sparx5 VCAP
functionality.

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

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

Overview:
=========

The added flower filter key (dissector) support is this:

- ipv4_addr (sip and dip)
- ipv6_addr (sip and dip)
- control (IPv4 fragments)
- portnum (tcp and udp port numbers)
- basic (L3 and L4 protocol)
- vlan (outer vlan tag info)
- tcp (tcp flags)
- ip (tos field)

The IS2 VCAP supports classified VLAN information which amounts to the
outer VLAN info in case of multiple tags.

Functionality:
==============

Before frames can match IS2 VCAP rules with e.g an IPv4 source address, the
IS2 VCAPs keyset configuration must include keyset that contains a IPv4
source address and this must be configured for the lookup/port/traffic-type
that you want to match on.

The Sparx5 IS2 VCAP has the following traffic types:

- Non-Ethernet frames
- IPv4 Unicast frames
- IPv4 Multicast frames
- IPv6 Unicast frames
- IPv6 Multicast frames
- ARP frames

So to cover IPv4 traffic the two IPv4 categories must be configured with a
keyset that contains IPv4 address information such as the
VCAP_KFS_IP4_TCP_UDP keyset.

The IPv4 and IPv6 traffic types are configured with useful default keysets,
in later series we will use the tc template functionality when we want to
change these defaults.

The flower filter must contain a goto action as its last action and the
chain id must specify the chain id of the next lookup in a VCAP or a
destination outside the VCAP ranges.

To activate the VCAP lookups on a port you must add a TC matchall filter on
the port containing a single goto action that points to the chain id of the
first lookup in the IS2 VCAP.

From then on frames arriving on this port will be matched against the
rules in the IS2 VCAP lookups.

Removing the matchall filter will deactivate the IS2 lookups, but will
leave the VCAP rules in the memory of the VCAP instance, and from then in
frames will no longer be matched against the rules the in IS2 VCAP.

If the matchall rule is added back again the IS2 rules will be active
once more.

Delivery:
=========

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

- TC flower filter statistics and rule order by size and priority
- debugfs support for inspecting rules
- support for TC protocol all
- Sparx5 IS0 VCAP support
- add 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

Version History:
================
v6      Rebased on the latest next-next master branch.
        No other implementation changes.

v5      Add support for a TC matchall filter with a single goto action
        which will activate the lookups of the VCAP.  Removing this filter
        will deactivate the VCAP lookups again.

v4      Add support for TC flower filter goto action and a check of the
        actions: check action combinations and the goto chain id.

v3      Add some more details to the explanation in the commit message
        about support for MAC_ETYPE keysets and "protocol all" as well as
        the classified VLAN information.  This is done to help testing the
        feature.
        No implementation changes in this version.

v2      Split one of the KUNIT tests into 3 tests to fix a kernel robot
        build warning.

v1      Initial version
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 573c3853 c956b9b3
......@@ -9,7 +9,7 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \
sparx5_netdev.o sparx5_phylink.o sparx5_port.o sparx5_mactable.o sparx5_vlan.o \
sparx5_switchdev.o sparx5_calendar.o sparx5_ethtool.o sparx5_fdma.o \
sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o
sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o sparx5_tc_matchall.o
sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
......
......@@ -19,9 +19,14 @@ static int sparx5_tc_block_cb(enum tc_setup_type type,
{
struct net_device *ndev = cb_priv;
if (type == TC_SETUP_CLSFLOWER)
switch (type) {
case TC_SETUP_CLSMATCHALL:
return sparx5_tc_matchall(ndev, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return sparx5_tc_flower(ndev, type_data, ingress);
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
}
static int sparx5_tc_block_cb_ingress(enum tc_setup_type type,
......
......@@ -8,6 +8,7 @@
#define __SPARX5_TC_H__
#include <net/flow_offload.h>
#include <net/pkt_cls.h>
#include <linux/netdevice.h>
/* Controls how PORT_MASK is applied */
......@@ -23,6 +24,10 @@ enum SPX5_PORT_MASK_MODE {
int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
int sparx5_tc_matchall(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress);
int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
bool ingress);
......
// SPDX-License-Identifier: GPL-2.0+
/* Microchip VCAP API
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/
#include "sparx5_tc.h"
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "sparx5_main_regs.h"
#include "sparx5_main.h"
#include "sparx5_vcap_impl.h"
static int sparx5_tc_matchall_replace(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct flow_action_entry *action;
struct sparx5 *sparx5;
int err;
if (!flow_offload_has_one_action(&tmo->rule->action)) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Only one action per filter is supported");
return -EOPNOTSUPP;
}
action = &tmo->rule->action.entries[0];
sparx5 = port->sparx5;
switch (action->id) {
case FLOW_ACTION_GOTO:
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
action->chain_index, tmo->cookie,
true);
if (err == -EFAULT) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Unsupported goto chain");
return -EOPNOTSUPP;
}
if (err == -EADDRINUSE) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"VCAP already enabled");
return -EOPNOTSUPP;
}
if (err) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Could not enable VCAP lookups");
return err;
}
break;
default:
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
return -EOPNOTSUPP;
}
return 0;
}
static int sparx5_tc_matchall_destroy(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5;
int err;
sparx5 = port->sparx5;
if (!tmo->rule && tmo->cookie) {
err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev, 0,
tmo->cookie, false);
if (err)
return err;
return 0;
}
NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
return -EOPNOTSUPP;
}
int sparx5_tc_matchall(struct net_device *ndev,
struct tc_cls_matchall_offload *tmo,
bool ingress)
{
if (!tc_cls_can_offload_and_chain0(ndev, &tmo->common)) {
NL_SET_ERR_MSG_MOD(tmo->common.extack,
"Only chain zero is supported");
return -EOPNOTSUPP;
}
switch (tmo->command) {
case TC_CLSMATCHALL_REPLACE:
return sparx5_tc_matchall_replace(ndev, tmo, ingress);
case TC_CLSMATCHALL_DESTROY:
return sparx5_tc_matchall_destroy(ndev, tmo, ingress);
default:
return -EOPNOTSUPP;
}
}
......@@ -21,6 +21,14 @@
#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */
#define SPARX5_IS2_LOOKUPS 4
#define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \
(ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \
ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \
ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(_v4_mc) | \
ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(_v4_uc) | \
ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(_v6_mc) | \
ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \
ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp))
/* IS2 port keyset selection control */
......@@ -152,7 +160,7 @@ static const char *sparx5_vcap_keyset_name(struct net_device *ndev,
{
struct sparx5_port *port = netdev_priv(ndev);
return port->sparx5->vcap_ctrl->stats->keyfield_set_names[keyset];
return vcap_keyset_name(port->sparx5->vcap_ctrl, keyset);
}
/* Check if this is the first lookup of IS2 */
......@@ -196,6 +204,127 @@ static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule,
vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask);
}
/* Convert chain id to vcap lookup id */
static int sparx5_vcap_cid_to_lookup(int cid)
{
int lookup = 0;
/* For now only handle IS2 */
if (cid >= SPARX5_VCAP_CID_IS2_L1 && cid < SPARX5_VCAP_CID_IS2_L2)
lookup = 1;
else if (cid >= SPARX5_VCAP_CID_IS2_L2 && cid < SPARX5_VCAP_CID_IS2_L3)
lookup = 2;
else if (cid >= SPARX5_VCAP_CID_IS2_L3 && cid < SPARX5_VCAP_CID_IS2_MAX)
lookup = 3;
return lookup;
}
/* Return the list of keysets for the vcap port configuration */
static int sparx5_vcap_is2_get_port_keysets(struct net_device *ndev,
int lookup,
struct vcap_keyset_list *keysetlist,
u16 l3_proto)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
int portno = port->portno;
u32 value;
/* Check if the port keyset selection is enabled */
value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
if (!ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_GET(value))
return -ENOENT;
/* Collect all keysets for the port in a list */
if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_ARP_MAC_ETYPE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
case VCAP_IS2_PS_ARP_ARP:
vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
break;
}
}
if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
break;
case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
break;
}
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
break;
case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
break;
}
}
if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
break;
case VCAP_IS2_PS_IPV6_UC_IP6_STD:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
break;
case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
break;
}
switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
break;
case VCAP_IS2_PS_IPV6_MC_IP6_STD:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
break;
case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
break;
case VCAP_IS2_PS_IPV6_MC_IP6_VID:
/* Not used */
break;
}
}
if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP &&
l3_proto != ETH_P_IPV6) {
switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {
case VCAP_IS2_PS_NONETH_MAC_ETYPE:
/* IS2 non-classified frames generate MAC_ETYPE */
vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
break;
}
}
return 0;
}
/* API callback used for validating a field keyset (check the port keysets) */
static enum vcap_keyfield_set
sparx5_vcap_validate_keyset(struct net_device *ndev,
......@@ -204,10 +333,30 @@ sparx5_vcap_validate_keyset(struct net_device *ndev,
struct vcap_keyset_list *kslist,
u16 l3_proto)
{
struct vcap_keyset_list keysetlist = {};
enum vcap_keyfield_set keysets[10] = {};
int idx, jdx, lookup;
if (!kslist || kslist->cnt == 0)
return VCAP_KFS_NO_VALUE;
/* for now just return whatever the API suggests */
return kslist->keysets[0];
/* Get a list of currently configured keysets in the lookups */
lookup = sparx5_vcap_cid_to_lookup(rule->vcap_chain_id);
keysetlist.max = ARRAY_SIZE(keysets);
keysetlist.keysets = keysets;
sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist, l3_proto);
/* Check if there is a match and return the match */
for (idx = 0; idx < kslist->cnt; ++idx)
for (jdx = 0; jdx < keysetlist.cnt; ++jdx)
if (kslist->keysets[idx] == keysets[jdx])
return kslist->keysets[idx];
pr_err("%s:%d: %s not supported in port key selection\n",
__func__, __LINE__,
sparx5_vcap_keyset_name(ndev, kslist->keysets[0]));
return -ENOENT;
}
/* API callback used for adding default fields to a rule */
......@@ -340,6 +489,28 @@ static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype,
return 0;
}
/* Enable all lookups in the VCAP instance */
static int sparx5_vcap_enable(struct net_device *ndev,
struct vcap_admin *admin,
bool enable)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5;
int portno;
sparx5 = port->sparx5;
portno = port->portno;
/* For now we only consider IS2 */
if (enable)
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
else
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
return 0;
}
/* API callback operations: only IS2 is supported for now */
static struct vcap_operations sparx5_vcap_ops = {
.validate_keyset = sparx5_vcap_validate_keyset,
......@@ -351,6 +522,7 @@ static struct vcap_operations sparx5_vcap_ops = {
.update = sparx5_vcap_update,
.move = sparx5_vcap_move,
.port_info = sparx5_port_info,
.enable = sparx5_vcap_enable,
};
/* Enable lookups per port and set the keyset generation: only IS2 for now */
......@@ -360,21 +532,15 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
int portno, lookup;
u32 keysel;
/* enable all 4 lookups on all ports */
for (portno = 0; portno < SPX5_PORTS; ++portno)
spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
ANA_ACL_VCAP_S2_CFG(portno));
/* all traffic types generate the MAC_ETYPE keyset for now in all
* lookups on all ports
*/
keysel = ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(true) |
ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(VCAP_IS2_PS_NONETH_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_MC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_UC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_MC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_UC_MAC_ETYPE) |
ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(VCAP_IS2_PS_ARP_MAC_ETYPE);
keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE,
VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
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);
for (lookup = 0; lookup < admin->lookups; ++lookup) {
for (portno = 0; portno < SPX5_PORTS; ++portno) {
spx5_wr(keysel, sparx5,
......@@ -418,6 +584,7 @@ sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
INIT_LIST_HEAD(&admin->enabled);
admin->vtype = cfg->vtype;
admin->vinst = cfg->vinst;
admin->lookups = cfg->lookups;
......
......@@ -166,6 +166,7 @@ enum vcap_rule_error {
struct vcap_admin {
struct list_head list; /* for insertion in vcap_control */
struct list_head rules; /* list of rules */
struct list_head enabled; /* list of enabled ports */
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
int first_cid; /* first chain id in this vcap */
......@@ -255,6 +256,11 @@ struct vcap_operations {
int (*pf)(void *out, int arg, const char *fmt, ...),
void *out,
int arg);
/* enable/disable the lookups in a vcap instance */
int (*enable)
(struct net_device *ndev,
struct vcap_admin *admin,
bool enable);
};
/* VCAP API Client control interface */
......
......@@ -143,6 +143,10 @@ enum vcap_bit {
VCAP_BIT_1
};
/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int chain_id, unsigned long cookie, bool enable);
/* VCAP rule operations */
/* Allocate a rule and fill in the basic information */
struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl,
......@@ -176,12 +180,16 @@ int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key,
struct vcap_u48_key *fieldval);
int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key,
struct vcap_u72_key *fieldval);
int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
struct vcap_u128_key *fieldval);
int vcap_rule_add_action_bit(struct vcap_rule *rule,
enum vcap_action_field action, enum vcap_bit val);
int vcap_rule_add_action_u32(struct vcap_rule *rule,
enum vcap_action_field action, u32 value);
/* VCAP lookup operations */
/* Convert a chain id to a VCAP lookup index */
int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid);
/* Lookup a vcap instance using chain id */
struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid);
/* Find information on a key field in a rule */
......@@ -189,6 +197,8 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
enum vcap_key_field key);
/* Find a rule id with a provided cookie */
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);
/* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
......@@ -199,4 +209,15 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule);
/* Cleanup a VCAP instance */
int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin);
/* Add a keyset to a keyset list */
bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
enum vcap_keyfield_set keyset);
/* map keyset id to a string with the keyset name */
const char *vcap_keyset_name(struct vcap_control *vctrl,
enum vcap_keyfield_set keyset);
/* map key field id to a string with the key name */
const char *vcap_keyfield_name(struct vcap_control *vctrl,
enum vcap_key_field key);
#endif /* __VCAP_API_CLIENT__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment