Commit 166a1a5a authored by David S. Miller's avatar David S. Miller

Merge branch 'sparx5-ES2-VCAP-support'

Steen Hegelund says:

====================
Adding Sparx5 ES2 VCAP support

This provides the Egress Stage 2 (ES2) VCAP (Versatile Content-Aware
Processor) support for the Sparx5 platform.

The ES2 VCAP is an Egress Access Control VCAP that uses frame keyfields and
previously classified keyfields to apply e.g. policing, trapping or
mirroring to frames.

The ES2 VCAP has 2 lookups and they are accessible with a TC chain id:

- chain 20000000: ES2 Lookup 0
- chain 20100000: ES2 Lookup 1

As the other Sparx5 VCAPs the ES2 VCAP has its own lookup/port keyset
configuration that decides which keys will be used for matching on which
traffic type.

The ES2 VCAP has these traffic classifications:

- IPv4 frames
- IPv6 frames
- Other frames

The ES2 VCAP can match on an ISDX key (Ingress Service Index) as one of the
frame metadata keyfields.  The IS0 VCAP can update this key using its
actions, and this allows a IS0 VCAP rule to be linked to an ES2 rule.

This is similar to how the IS0 VCAP and the IS2 VCAP use the PAG
(Policy Association Group) keyfield to link rules.

From user space this is exposed via "chain offsets", so an IS0 rule with a
"goto chain 20000015" action will use an ISDX key value of 15 to link to a
rule in the ES2 VCAP attached to the same chain id.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5dd3beba 1f741f00
......@@ -603,7 +603,8 @@ int lan966x_vcap_init(struct lan966x *lan966x);
void lan966x_vcap_deinit(struct lan966x *lan966x);
int lan966x_tc_flower(struct lan966x_port *port,
struct flow_cls_offload *f);
struct flow_cls_offload *f,
bool ingress);
int lan966x_goto_port_add(struct lan966x_port *port,
int from_cid, int to_cid,
......
......@@ -70,7 +70,7 @@ static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
case TC_SETUP_CLSMATCHALL:
return lan966x_tc_matchall(port, type_data, ingress);
case TC_SETUP_CLSFLOWER:
return lan966x_tc_flower(port, type_data);
return lan966x_tc_flower(port, type_data, ingress);
default:
return -EOPNOTSUPP;
}
......
......@@ -83,7 +83,8 @@ static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
struct net_device *dev,
struct flow_cls_offload *fco)
struct flow_cls_offload *fco,
bool ingress)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL;
......@@ -120,7 +121,8 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
"Invalid goto chain");
return -EINVAL;
}
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) {
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
ingress)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Last action must be 'goto'");
return -EINVAL;
......@@ -139,7 +141,8 @@ static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
static int lan966x_tc_flower_add(struct lan966x_port *port,
struct flow_cls_offload *f,
struct vcap_admin *admin)
struct vcap_admin *admin,
bool ingress)
{
struct flow_action_entry *act;
u16 l3_proto = ETH_P_ALL;
......@@ -148,7 +151,7 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
int err, idx;
err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl,
port->dev, f);
port->dev, f, ingress);
if (err)
return err;
......@@ -232,7 +235,8 @@ static int lan966x_tc_flower_del(struct lan966x_port *port,
}
int lan966x_tc_flower(struct lan966x_port *port,
struct flow_cls_offload *f)
struct flow_cls_offload *f,
bool ingress)
{
struct vcap_admin *admin;
......@@ -245,7 +249,7 @@ int lan966x_tc_flower(struct lan966x_port *port,
switch (f->command) {
case FLOW_CLS_REPLACE:
return lan966x_tc_flower_add(port, f, admin);
return lan966x_tc_flower_add(port, f, admin, ingress);
case FLOW_CLS_DESTROY:
return lan966x_tc_flower_del(port, f, admin);
default:
......
......@@ -23,6 +23,7 @@ static struct lan966x_vcap_inst {
int first_cid; /* first chain id in this vcap */
int last_cid; /* last chain id in this vcap */
int count; /* number of available addresses */
bool ingress; /* is vcap in the ingress path */
} lan966x_vcap_inst_cfg[] = {
{
.vtype = VCAP_TYPE_IS2, /* IS2-0 */
......@@ -31,6 +32,7 @@ static struct lan966x_vcap_inst {
.first_cid = LAN966X_VCAP_CID_IS2_L0,
.last_cid = LAN966X_VCAP_CID_IS2_MAX,
.count = 256,
.ingress = true,
},
};
......@@ -431,6 +433,7 @@ lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
admin->vtype = cfg->vtype;
admin->vinst = 0;
admin->ingress = cfg->ingress;
admin->w32be = true;
admin->tgt_inst = cfg->tgt_inst;
......
......@@ -198,6 +198,7 @@ static const struct sparx5_main_io_resource sparx5_main_iomap[] = {
{ TARGET_QSYS, 0x110a0000, 2 }, /* 0x6110a0000 */
{ TARGET_QFWD, 0x110b0000, 2 }, /* 0x6110b0000 */
{ TARGET_XQS, 0x110c0000, 2 }, /* 0x6110c0000 */
{ TARGET_VCAP_ES2, 0x110d0000, 2 }, /* 0x6110d0000 */
{ TARGET_CLKGEN, 0x11100000, 2 }, /* 0x611100000 */
{ TARGET_ANA_AC_POL, 0x11200000, 2 }, /* 0x611200000 */
{ TARGET_QRES, 0x11280000, 2 }, /* 0x611280000 */
......
......@@ -266,6 +266,14 @@ sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st)
VCAP_BIT_0);
if (err)
goto out;
if (st->admin->vtype == VCAP_TYPE_IS0) {
err = vcap_rule_add_key_bit(st->vrule,
VCAP_KF_IP_SNAP_IS,
VCAP_BIT_1);
if (err)
goto out;
}
}
}
......@@ -317,8 +325,11 @@ sparx5_tc_flower_handler_cvlan_usage(struct sparx5_tc_flower_parse_usage *st)
u16 tpid;
int err;
if (st->admin->vtype != VCAP_TYPE_IS0)
if (st->admin->vtype != VCAP_TYPE_IS0) {
NL_SET_ERR_MSG_MOD(st->fco->common.extack,
"cvlan not supported in this VCAP");
return -EINVAL;
}
flow_rule_match_cvlan(st->frule, &mt);
......@@ -607,7 +618,8 @@ static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
struct net_device *ndev,
struct flow_cls_offload *fco)
struct flow_cls_offload *fco,
bool ingress)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
struct flow_action_entry *actent, *last_actent = NULL;
......@@ -644,7 +656,8 @@ static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
"Invalid goto chain");
return -EINVAL;
}
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index)) {
} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
ingress)) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Last action must be 'goto'");
return -EINVAL;
......@@ -667,7 +680,7 @@ static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
{
int err;
if (admin->vtype == VCAP_TYPE_IS2) {
if (admin->vtype == VCAP_TYPE_IS2 || admin->vtype == VCAP_TYPE_ES2) {
err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
vrule->id);
if (err)
......@@ -870,6 +883,9 @@ static int sparx5_tc_set_actionset(struct vcap_admin *admin,
case VCAP_TYPE_IS2:
aset = VCAP_AFS_BASE_TYPE;
break;
case VCAP_TYPE_ES2:
aset = VCAP_AFS_BASE_TYPE;
break;
default:
return -EINVAL;
}
......@@ -906,6 +922,10 @@ static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
link_val, /* target */
~0);
case VCAP_TYPE_ES2:
/* Add ISDX key for chaining rules from IS0 */
return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
~0);
default:
break;
}
......@@ -948,6 +968,18 @@ static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
0xff);
if (err)
goto out;
} else if (admin->vtype == VCAP_TYPE_IS0 &&
to_admin->vtype == VCAP_TYPE_ES2) {
/* Between IS0 and ES2 the ISDX value is used */
err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
diff);
if (err)
goto out;
err = vcap_rule_add_action_bit(vrule,
VCAP_AF_ISDX_ADD_REPLACE_SEL,
VCAP_BIT_1);
if (err)
goto out;
} else {
pr_err("%s:%d: unsupported chain destination: %d\n",
__func__, __LINE__, to_cid);
......@@ -959,7 +991,8 @@ static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
static int sparx5_tc_flower_replace(struct net_device *ndev,
struct flow_cls_offload *fco,
struct vcap_admin *admin)
struct vcap_admin *admin,
bool ingress)
{
struct sparx5_port *port = netdev_priv(ndev);
struct sparx5_multiple_rules multi = {};
......@@ -972,7 +1005,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
vctrl = port->sparx5->vcap_ctrl;
err = sparx5_tc_flower_action_check(vctrl, ndev, fco);
err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
if (err)
return err;
......@@ -1001,7 +1034,8 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
flow_action_for_each(idx, act, &frule->action) {
switch (act->id) {
case FLOW_ACTION_TRAP:
if (admin->vtype != VCAP_TYPE_IS2) {
if (admin->vtype != VCAP_TYPE_IS2 &&
admin->vtype != VCAP_TYPE_ES2) {
NL_SET_ERR_MSG_MOD(fco->common.extack,
"Trap action not supported in this VCAP");
err = -EOPNOTSUPP;
......@@ -1016,8 +1050,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev,
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 (admin->vtype != VCAP_TYPE_IS2)
break;
err = vcap_rule_add_action_u32(vrule,
VCAP_AF_MASK_MODE,
SPX5_PMM_REPLACE_ALL);
if (err)
goto out;
break;
......@@ -1130,7 +1167,7 @@ int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
switch (fco->command) {
case FLOW_CLS_REPLACE:
return sparx5_tc_flower_replace(ndev, fco, admin);
return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
case FLOW_CLS_DESTROY:
return sparx5_tc_flower_destroy(ndev, fco, admin);
case FLOW_CLS_STATS:
......
......@@ -284,6 +284,119 @@ static void sparx5_vcap_is2_port_stickies(struct sparx5 *sparx5,
out->prf(out->dst, "\n");
}
static void sparx5_vcap_es2_port_keys(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct sparx5_port *port,
struct vcap_output_print *out)
{
int lookup;
u32 value;
out->prf(out->dst, " port[%02d] (%s): ", port->portno,
netdev_name(port->ndev));
for (lookup = 0; lookup < admin->lookups; ++lookup) {
out->prf(out->dst, "\n Lookup %d: ", lookup);
/* Get lookup state */
value = spx5_rd(sparx5, EACL_VCAP_ES2_KEY_SEL(port->portno,
lookup));
out->prf(out->dst, "\n state: ");
if (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_GET(value))
out->prf(out->dst, "on");
else
out->prf(out->dst, "off");
out->prf(out->dst, "\n arp: ");
switch (EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
case VCAP_ES2_PS_ARP_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_ES2_PS_ARP_ARP:
out->prf(out->dst, "arp");
break;
}
out->prf(out->dst, "\n ipv4: ");
switch (EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_GET(value)) {
case VCAP_ES2_PS_IPV4_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_ES2_PS_IPV4_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_VID:
out->prf(out->dst, "ip4_tcp_udp ip4_vid");
break;
case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER:
out->prf(out->dst, "ip4_tcp_udp ip4_other");
break;
case VCAP_ES2_PS_IPV4_IP4_VID:
out->prf(out->dst, "ip4_vid");
break;
case VCAP_ES2_PS_IPV4_IP4_OTHER:
out->prf(out->dst, "ip4_other");
break;
}
out->prf(out->dst, "\n ipv6: ");
switch (EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_GET(value)) {
case VCAP_ES2_PS_IPV6_MAC_ETYPE:
out->prf(out->dst, "mac_etype");
break;
case VCAP_ES2_PS_IPV6_IP_7TUPLE:
out->prf(out->dst, "ip_7tuple");
break;
case VCAP_ES2_PS_IPV6_IP_7TUPLE_VID:
out->prf(out->dst, "ip_7tuple ip6_vid");
break;
case VCAP_ES2_PS_IPV6_IP_7TUPLE_STD:
out->prf(out->dst, "ip_7tuple ip6_std");
break;
case VCAP_ES2_PS_IPV6_IP6_VID:
out->prf(out->dst, "ip6_vid");
break;
case VCAP_ES2_PS_IPV6_IP6_STD:
out->prf(out->dst, "ip6_std");
break;
case VCAP_ES2_PS_IPV6_IP4_DOWNGRADE:
out->prf(out->dst, "ip4_downgrade");
break;
}
}
out->prf(out->dst, "\n");
}
static void sparx5_vcap_es2_port_stickies(struct sparx5 *sparx5,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
int lookup;
u32 value;
out->prf(out->dst, " Sticky bits: ");
for (lookup = 0; lookup < admin->lookups; ++lookup) {
value = spx5_rd(sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
out->prf(out->dst, "\n Lookup %d: ", lookup);
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
out->prf(out->dst, " ip_7tuple");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
out->prf(out->dst, " ip6_vid");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
out->prf(out->dst, " ip6_std");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
out->prf(out->dst, " ip4_tcp_udp");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
out->prf(out->dst, " ip4_vid");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
out->prf(out->dst, " ip4_other");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
out->prf(out->dst, " arp");
if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
out->prf(out->dst, " mac_etype");
/* Clear stickies */
spx5_wr(value, sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
}
out->prf(out->dst, "\n");
}
/* Provide port information via a callback interface */
int sparx5_port_info(struct net_device *ndev,
struct vcap_admin *admin,
......@@ -305,6 +418,10 @@ int sparx5_port_info(struct net_device *ndev,
sparx5_vcap_is2_port_keys(sparx5, admin, port, out);
sparx5_vcap_is2_port_stickies(sparx5, admin, out);
break;
case VCAP_TYPE_ES2:
sparx5_vcap_es2_port_keys(sparx5, admin, port, out);
sparx5_vcap_es2_port_stickies(sparx5, admin, out);
break;
default:
out->prf(out->dst, " no info\n");
break;
......
......@@ -32,6 +32,11 @@
#define SPARX5_VCAP_CID_IS2_MAX \
(VCAP_CID_INGRESS_STAGE2_L3 + VCAP_CID_LOOKUP_SIZE - 1) /* IS2 Max */
#define SPARX5_VCAP_CID_ES2_L0 VCAP_CID_EGRESS_STAGE2_L0 /* ES2 lookup 0 */
#define SPARX5_VCAP_CID_ES2_L1 VCAP_CID_EGRESS_STAGE2_L1 /* ES2 lookup 1 */
#define SPARX5_VCAP_CID_ES2_MAX \
(VCAP_CID_EGRESS_STAGE2_L1 + VCAP_CID_LOOKUP_SIZE - 1) /* ES2 Max */
/* IS0 port keyset selection control */
/* IS0 ethernet, IPv4, IPv6 traffic type keyset generation */
......@@ -129,6 +134,35 @@ enum vcap_is2_port_sel_arp {
VCAP_IS2_PS_ARP_ARP,
};
/* ES2 port keyset selection control */
/* ES2 IPv4 traffic type keyset generation */
enum vcap_es2_port_sel_ipv4 {
VCAP_ES2_PS_IPV4_MAC_ETYPE,
VCAP_ES2_PS_IPV4_IP_7TUPLE,
VCAP_ES2_PS_IPV4_IP4_TCP_UDP_VID,
VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER,
VCAP_ES2_PS_IPV4_IP4_VID,
VCAP_ES2_PS_IPV4_IP4_OTHER,
};
/* ES2 IPv6 traffic type keyset generation */
enum vcap_es2_port_sel_ipv6 {
VCAP_ES2_PS_IPV6_MAC_ETYPE,
VCAP_ES2_PS_IPV6_IP_7TUPLE,
VCAP_ES2_PS_IPV6_IP_7TUPLE_VID,
VCAP_ES2_PS_IPV6_IP_7TUPLE_STD,
VCAP_ES2_PS_IPV6_IP6_VID,
VCAP_ES2_PS_IPV6_IP6_STD,
VCAP_ES2_PS_IPV6_IP4_DOWNGRADE,
};
/* ES2 ARP traffic type keyset generation */
enum vcap_es2_port_sel_arp {
VCAP_ES2_PS_ARP_MAC_ETYPE,
VCAP_ES2_PS_ARP_ARP,
};
/* Get the port keyset for the vcap lookup */
int sparx5_vcap_get_port_keyset(struct net_device *ndev,
struct vcap_admin *admin,
......
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
/* This file is autogenerated by cml-utils 2022-12-06 09:49:28 +0100.
* Commit ID: cd9451f1b9d8cafa58f845de66a6e373658019ef
/* This file is autogenerated by cml-utils 2023-01-17 16:52:16 +0100.
* Commit ID: 229ec79be5df142c1f335a01d0e63232d4feb2ba
*/
#ifndef __VCAP_AG_API__
......@@ -276,7 +276,8 @@ enum vcap_keyfield_set {
* Select the mode of the Generic Index
* VCAP_KF_LOOKUP_PAG: W8, sparx5: is2, lan966x: is2
* Classified Policy Association Group: chains rules from IS1/CLM to IS2
* VCAP_KF_MIRROR_ENA: *** No docstring ***
* VCAP_KF_MIRROR_PROBE: W2, sparx5: es2
* Identifies frame copies generated as a result of mirroring
* VCAP_KF_OAM_CCM_CNTS_EQ0: W1, sparx5: is2/es2, lan966x: is2
* Dual-ended loss measurement counters in CCM frames are all zero
* VCAP_KF_OAM_DETECTED: W1, lan966x: is2
......@@ -407,7 +408,7 @@ enum vcap_key_field {
VCAP_KF_LOOKUP_GEN_IDX,
VCAP_KF_LOOKUP_GEN_IDX_SEL,
VCAP_KF_LOOKUP_PAG,
VCAP_KF_MIRROR_ENA,
VCAP_KF_MIRROR_PROBE,
VCAP_KF_OAM_CCM_CNTS_EQ0,
VCAP_KF_OAM_DETECTED,
VCAP_KF_OAM_FLAGS,
......
......@@ -1601,15 +1601,17 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid)
}
EXPORT_SYMBOL_GPL(vcap_find_admin);
/* Is this the last admin instance ordered by chain id */
/* Is this the last admin instance ordered by chain id and direction */
static bool vcap_admin_is_last(struct vcap_control *vctrl,
struct vcap_admin *admin)
struct vcap_admin *admin,
bool ingress)
{
struct vcap_admin *iter, *last = NULL;
int max_cid = 0;
list_for_each_entry(iter, &vctrl->list, list) {
if (iter->first_cid > max_cid) {
if (iter->first_cid > max_cid &&
iter->ingress == ingress) {
last = iter;
max_cid = iter->first_cid;
}
......@@ -3177,7 +3179,7 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
EXPORT_SYMBOL_GPL(vcap_enable_lookups);
/* Is this chain id the last lookup of all VCAPs */
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid)
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress)
{
struct vcap_admin *admin;
int lookup;
......@@ -3189,7 +3191,7 @@ bool vcap_is_last_chain(struct vcap_control *vctrl, int cid)
if (!admin)
return false;
if (!vcap_admin_is_last(vctrl, admin))
if (!vcap_admin_is_last(vctrl, admin, ingress))
return false;
/* This must be the last lookup in this VCAP type */
......@@ -3264,6 +3266,28 @@ static int vcap_rule_get_key(struct vcap_rule *rule,
return 0;
}
/* Find a keyset having the same size as the provided rule, where the keyset
* does not have a type id.
*/
static int vcap_rule_get_untyped_keyset(struct vcap_rule_internal *ri,
struct vcap_keyset_list *matches)
{
struct vcap_control *vctrl = ri->vctrl;
enum vcap_type vt = ri->admin->vtype;
const struct vcap_set *keyfield_set;
int idx;
keyfield_set = vctrl->vcaps[vt].keyfield_set;
for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
if (keyfield_set[idx].sw_per_item == ri->keyset_sw &&
keyfield_set[idx].type_id == (u8)-1) {
vcap_keyset_list_add(matches, idx);
return 0;
}
}
return -EINVAL;
}
/* Get the keysets that matches the rule key type/mask */
int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
struct vcap_keyset_list *matches)
......@@ -3277,7 +3301,7 @@ int vcap_rule_get_keysets(struct vcap_rule_internal *ri,
err = vcap_rule_get_key(&ri->data, VCAP_KF_TYPE, &kf);
if (err)
return err;
return vcap_rule_get_untyped_keyset(ri, matches);
if (kf.ctrl.type == VCAP_FIELD_BIT) {
value = kf.data.u1.value;
......
......@@ -176,6 +176,7 @@ struct vcap_admin {
int first_valid_addr; /* bottom of address range to be used */
int last_used_addr; /* address of lowest added rule */
bool w32be; /* vcap uses "32bit-word big-endian" encoding */
bool ingress; /* chain traffic direction */
struct vcap_cache_data cache; /* encoded rule data */
};
......
......@@ -222,7 +222,7 @@ int vcap_chain_offset(struct vcap_control *vctrl, int from_cid, int to_cid);
/* 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);
/* Is this chain id the last lookup of all VCAPs */
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid);
bool vcap_is_last_chain(struct vcap_control *vctrl, int cid, bool ingress);
/* Provide all rules via a callback interface */
int vcap_rule_iter(struct vcap_control *vctrl,
int (*callback)(void *, struct vcap_rule *), void *arg);
......
......@@ -44,11 +44,14 @@ static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
out->prf(out->dst, "%pI4h/%pI4h", &data->u32.value,
&data->u32.mask);
} else if (key == VCAP_KF_ETYPE ||
key == VCAP_KF_IF_IGR_PORT_MASK) {
key == VCAP_KF_IF_IGR_PORT_MASK ||
key == VCAP_KF_IF_EGR_PORT_MASK) {
hex = true;
} else {
u32 fmsk = (1 << keyfield[key].width) - 1;
if (keyfield[key].width == 32)
fmsk = ~0;
out->prf(out->dst, "%u/%u", data->u32.value & fmsk,
data->u32.mask & fmsk);
}
......@@ -277,6 +280,7 @@ static void vcap_show_admin_info(struct vcap_control *vctrl,
out->prf(out->dst, "version: %d\n", vcap->version);
out->prf(out->dst, "vtype: %d\n", admin->vtype);
out->prf(out->dst, "vinst: %d\n", admin->vinst);
out->prf(out->dst, "ingress: %d\n", admin->ingress);
out->prf(out->dst, "first_cid: %d\n", admin->first_cid);
out->prf(out->dst, "last_cid: %d\n", admin->last_cid);
out->prf(out->dst, "lookups: %d\n", admin->lookups);
......
......@@ -389,6 +389,7 @@ static const char * const test_admin_info_expect[] = {
"version: 1\n",
"vtype: 2\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 10000\n",
"last_cid: 19999\n",
"lookups: 4\n",
......@@ -407,6 +408,7 @@ static void vcap_api_show_admin_test(struct kunit *test)
.last_valid_addr = 3071,
.first_valid_addr = 0,
.last_used_addr = 794,
.ingress = true,
};
struct vcap_output_print out = {
.prf = (void *)test_prf,
......@@ -435,6 +437,7 @@ static const char * const test_admin_expect[] = {
"version: 1\n",
"vtype: 2\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 8000000\n",
"last_cid: 8199999\n",
"lookups: 4\n",
......@@ -496,6 +499,7 @@ static void vcap_api_show_admin_rule_test(struct kunit *test)
.last_valid_addr = 3071,
.first_valid_addr = 0,
.last_used_addr = 794,
.ingress = true,
.cache = {
.keystream = keydata,
.maskstream = mskdata,
......
......@@ -2145,6 +2145,71 @@ static void vcap_api_filter_keylist_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, 26, idx);
}
static void vcap_api_rule_chain_path_test(struct kunit *test)
{
struct vcap_admin admin1 = {
.vtype = VCAP_TYPE_IS0,
.vinst = 0,
.first_cid = 1000000,
.last_cid = 1199999,
.lookups = 6,
.lookups_per_instance = 2,
};
struct vcap_enabled_port eport3 = {
.ndev = &test_netdev,
.cookie = 0x100,
.src_cid = 0,
.dst_cid = 1000000,
};
struct vcap_enabled_port eport2 = {
.ndev = &test_netdev,
.cookie = 0x200,
.src_cid = 1000000,
.dst_cid = 1100000,
};
struct vcap_enabled_port eport1 = {
.ndev = &test_netdev,
.cookie = 0x300,
.src_cid = 1100000,
.dst_cid = 8000000,
};
bool ret;
int chain;
vcap_test_api_init(&admin1);
list_add_tail(&eport1.list, &admin1.enabled);
list_add_tail(&eport2.list, &admin1.enabled);
list_add_tail(&eport3.list, &admin1.enabled);
ret = vcap_path_exist(&test_vctrl, &test_netdev, 1000000);
KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_path_exist(&test_vctrl, &test_netdev, 1100000);
KUNIT_EXPECT_EQ(test, true, ret);
ret = vcap_path_exist(&test_vctrl, &test_netdev, 1200000);
KUNIT_EXPECT_EQ(test, false, ret);
chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 0);
KUNIT_EXPECT_EQ(test, 1000000, chain);
chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 1000000);
KUNIT_EXPECT_EQ(test, 1100000, chain);
chain = vcap_get_next_chain(&test_vctrl, &test_netdev, 1100000);
KUNIT_EXPECT_EQ(test, 8000000, chain);
}
static struct kunit_case vcap_api_rule_enable_test_cases[] = {
KUNIT_CASE(vcap_api_rule_chain_path_test),
{}
};
static struct kunit_suite vcap_api_rule_enable_test_suite = {
.name = "VCAP_API_Rule_Enable_Testsuite",
.test_cases = vcap_api_rule_enable_test_cases,
};
static struct kunit_suite vcap_api_rule_remove_test_suite = {
.name = "VCAP_API_Rule_Remove_Testsuite",
.test_cases = vcap_api_rule_remove_test_cases,
......@@ -2235,6 +2300,7 @@ static struct kunit_suite vcap_api_encoding_test_suite = {
.test_cases = vcap_api_encoding_test_cases,
};
kunit_test_suite(vcap_api_rule_enable_test_suite);
kunit_test_suite(vcap_api_rule_remove_test_suite);
kunit_test_suite(vcap_api_rule_insert_test_suite);
kunit_test_suite(vcap_api_rule_counter_test_suite);
......
......@@ -1709,7 +1709,7 @@ static const struct vcap_field es2_mac_etype_keyfield[] = {
.offset = 96,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 97,
.width = 2,
......@@ -1847,7 +1847,7 @@ static const struct vcap_field es2_arp_keyfield[] = {
.offset = 95,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 96,
.width = 2,
......@@ -2010,7 +2010,7 @@ static const struct vcap_field es2_ip4_tcp_udp_keyfield[] = {
.offset = 96,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 97,
.width = 2,
......@@ -2223,7 +2223,7 @@ static const struct vcap_field es2_ip4_other_keyfield[] = {
.offset = 96,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 97,
.width = 2,
......@@ -2376,7 +2376,7 @@ static const struct vcap_field es2_ip_7tuple_keyfield[] = {
.offset = 93,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 94,
.width = 2,
......@@ -2569,7 +2569,7 @@ static const struct vcap_field es2_ip4_vid_keyfield[] = {
.offset = 48,
.width = 1,
},
[VCAP_KF_MIRROR_ENA] = {
[VCAP_KF_MIRROR_PROBE] = {
.type = VCAP_FIELD_U32,
.offset = 49,
.width = 2,
......@@ -3847,7 +3847,7 @@ static const char * const vcap_keyfield_names[] = {
[VCAP_KF_LOOKUP_GEN_IDX] = "LOOKUP_GEN_IDX",
[VCAP_KF_LOOKUP_GEN_IDX_SEL] = "LOOKUP_GEN_IDX_SEL",
[VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG",
[VCAP_KF_MIRROR_ENA] = "MIRROR_ENA",
[VCAP_KF_MIRROR_PROBE] = "MIRROR_PROBE",
[VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0",
[VCAP_KF_OAM_DETECTED] = "OAM_DETECTED",
[VCAP_KF_OAM_FLAGS] = "OAM_FLAGS",
......
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