Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,53 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Microchip VCAP API configuration
#
if NET_VENDOR_MICROCHIP
config VCAP
bool "VCAP (Versatile Content-Aware Processor) library"
help
Provides the basic VCAP functionality for multiple Microchip switchcores
A VCAP is essentially a TCAM with rules consisting of
- Programmable key fields
- Programmable action fields
- A counter (which may be only one bit wide)
Besides this each VCAP has:
- A number of lookups
- A keyset configuration per port per lookup
The VCAP implementation provides switchcore independent handling of rules
and supports:
- Creating and deleting rules
- Updating and getting rules
The platform specific configuration as well as the platform specific model
of the VCAP instances are attached to the VCAP API and a client can then
access rules via the API in a platform independent way, with the
limitations that each VCAP has in terms of its supported keys and actions.
Different switchcores will have different VCAP instances with different
characteristics. Look in the datasheet for the VCAP specifications for the
specific switchcore.
config VCAP_KUNIT_TEST
bool "KUnit test for VCAP library" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on KUNIT=y && VCAP=y && y
select DEBUG_FS
default KUNIT_ALL_TESTS
help
This builds unit tests for the VCAP library.
For more information on KUnit and unit tests in general, please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
endif # NET_VENDOR_MICROCHIP
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Microchip VCAP API
#
obj-$(CONFIG_VCAP) += vcap.o
obj-$(CONFIG_VCAP_KUNIT_TEST) += vcap_model_kunit.o
vcap-$(CONFIG_DEBUG_FS) += vcap_api_debugfs.o
vcap-y += vcap_api.o vcap_tc.o
@@ -0,0 +1,906 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
/* This file is autogenerated by cml-utils 2023-03-13 10:16:42 +0100.
* Commit ID: 259f0efd6d6d91bfbf62858de153cc757b6bffa3 (dirty)
*/
#ifndef __VCAP_AG_API__
#define __VCAP_AG_API__
enum vcap_type {
VCAP_TYPE_ES0,
VCAP_TYPE_ES2,
VCAP_TYPE_IS0,
VCAP_TYPE_IS1,
VCAP_TYPE_IS2,
VCAP_TYPE_MAX
};
/* Keyfieldset names with origin information */
enum vcap_keyfield_set {
VCAP_KFS_NO_VALUE, /* initial value */
VCAP_KFS_5TUPLE_IP4, /* lan966x is1 X2 */
VCAP_KFS_5TUPLE_IP6, /* lan966x is1 X4 */
VCAP_KFS_7TUPLE, /* lan966x is1 X4 */
VCAP_KFS_ARP, /* sparx5 is2 X6, sparx5 es2 X6, lan966x is2 X2 */
VCAP_KFS_DBL_VID, /* lan966x is1 X1 */
VCAP_KFS_DMAC_VID, /* lan966x is1 X1 */
VCAP_KFS_ETAG, /* sparx5 is0 X2 */
VCAP_KFS_IP4_OTHER, /* sparx5 is2 X6, sparx5 es2 X6, lan966x is2 X2 */
VCAP_KFS_IP4_TCP_UDP, /* sparx5 is2 X6, sparx5 es2 X6, lan966x is2 X2 */
VCAP_KFS_IP4_VID, /* sparx5 es2 X3 */
VCAP_KFS_IP6_OTHER, /* lan966x is2 X4 */
VCAP_KFS_IP6_STD, /* sparx5 is2 X6, sparx5 es2 X6, lan966x is2 X2 */
VCAP_KFS_IP6_TCP_UDP, /* lan966x is2 X4 */
VCAP_KFS_IP6_VID, /* sparx5 es2 X6 */
VCAP_KFS_IP_7TUPLE, /* sparx5 is2 X12, sparx5 es2 X12 */
VCAP_KFS_ISDX, /* sparx5 es0 X1 */
VCAP_KFS_LL_FULL, /* sparx5 is0 X6 */
VCAP_KFS_MAC_ETYPE, /* sparx5 is2 X6, sparx5 es2 X6, lan966x is2 X2 */
VCAP_KFS_MAC_LLC, /* lan966x is2 X2 */
VCAP_KFS_MAC_SNAP, /* lan966x is2 X2 */
VCAP_KFS_NORMAL, /* lan966x is1 X2 */
VCAP_KFS_NORMAL_5TUPLE_IP4, /* sparx5 is0 X6 */
VCAP_KFS_NORMAL_7TUPLE, /* sparx5 is0 X12 */
VCAP_KFS_NORMAL_IP6, /* lan966x is1 X4 */
VCAP_KFS_OAM, /* lan966x is2 X2 */
VCAP_KFS_PURE_5TUPLE_IP4, /* sparx5 is0 X3 */
VCAP_KFS_RT, /* lan966x is1 X1 */
VCAP_KFS_SMAC_SIP4, /* lan966x is2 X1 */
VCAP_KFS_SMAC_SIP6, /* lan966x is2 X2 */
VCAP_KFS_VID, /* lan966x es0 X1 */
};
/* List of keyfields with description
*
* Keys ending in _IS are booleans derived from frame data
* Keys ending in _CLS are classified frame data
*
* VCAP_KF_8021BR_ECID_BASE: W12, sparx5: is0
* Used by 802.1BR Bridge Port Extension in an E-Tag
* VCAP_KF_8021BR_ECID_EXT: W8, sparx5: is0
* Used by 802.1BR Bridge Port Extension in an E-Tag
* VCAP_KF_8021BR_E_TAGGED: W1, sparx5: is0
* Set for frames containing an E-TAG (802.1BR Ethertype 893f)
* VCAP_KF_8021BR_GRP: W2, sparx5: is0
* E-Tag group bits in 802.1BR Bridge Port Extension
* VCAP_KF_8021BR_IGR_ECID_BASE: W12, sparx5: is0
* Used by 802.1BR Bridge Port Extension in an E-Tag
* VCAP_KF_8021BR_IGR_ECID_EXT: W8, sparx5: is0
* Used by 802.1BR Bridge Port Extension in an E-Tag
* VCAP_KF_8021CB_R_TAGGED_IS: W1, lan966x: is1
* Set if frame contains an RTAG: IEEE 802.1CB (FRER Redundancy tag, Ethertype
* 0xf1c1)
* VCAP_KF_8021Q_DEI0: W1, sparx5: is0, lan966x: is1
* First DEI in multiple vlan tags (outer tag or default port tag)
* VCAP_KF_8021Q_DEI1: W1, sparx5: is0, lan966x: is1
* Second DEI in multiple vlan tags (inner tag)
* VCAP_KF_8021Q_DEI2: W1, sparx5: is0
* Third DEI in multiple vlan tags (not always available)
* VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2/es2, lan966x: is2/es0
* Classified DEI
* VCAP_KF_8021Q_PCP0: W3, sparx5: is0, lan966x: is1
* First PCP in multiple vlan tags (outer tag or default port tag)
* VCAP_KF_8021Q_PCP1: W3, sparx5: is0, lan966x: is1
* Second PCP in multiple vlan tags (inner tag)
* VCAP_KF_8021Q_PCP2: W3, sparx5: is0
* Third PCP in multiple vlan tags (not always available)
* VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2/es2, lan966x: is2/es0
* Classified PCP
* VCAP_KF_8021Q_TPID: W3, sparx5: es0
* TPID for outer tag: 0: Customer TPID 1: Service TPID (88A8 or programmable)
* VCAP_KF_8021Q_TPID0: sparx5 is0 W3, lan966x is1 W1
* First TPIC in multiple vlan tags (outer tag or default port tag)
* VCAP_KF_8021Q_TPID1: sparx5 is0 W3, lan966x is1 W1
* Second TPID in multiple vlan tags (inner tag)
* VCAP_KF_8021Q_TPID2: W3, sparx5: is0
* Third TPID in multiple vlan tags (not always available)
* VCAP_KF_8021Q_VID0: W12, sparx5: is0, lan966x: is1
* First VID in multiple vlan tags (outer tag or default port tag)
* VCAP_KF_8021Q_VID1: W12, sparx5: is0, lan966x: is1
* Second VID in multiple vlan tags (inner tag)
* VCAP_KF_8021Q_VID2: W12, sparx5: is0
* Third VID in multiple vlan tags (not always available)
* VCAP_KF_8021Q_VID_CLS: sparx5 is2 W13, sparx5 es0 W13, sparx5 es2 W13,
* lan966x is2 W12, lan966x es0 W12
* Classified VID
* VCAP_KF_8021Q_VLAN_DBL_TAGGED_IS: W1, lan966x: is1
* Set if frame has two or more Q-tags. Independent of port VLAN awareness
* VCAP_KF_8021Q_VLAN_TAGGED_IS: W1, sparx5: is2/es2, lan966x: is1/is2
* Sparx5: Set if frame was received with a VLAN tag, LAN966x: Set if frame has
* one or more Q-tags. Independent of port VLAN awareness
* VCAP_KF_8021Q_VLAN_TAGS: W3, sparx5: is0
* Number of VLAN tags in frame: 0: Untagged, 1: Single tagged, 3: Double
* tagged, 7: Triple tagged
* VCAP_KF_ACL_GRP_ID: W8, sparx5: es2
* Used in interface map table
* VCAP_KF_ARP_ADDR_SPACE_OK_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if hardware address is Ethernet
* VCAP_KF_ARP_LEN_OK_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if hardware address length = 6 (Ethernet) and IP address length = 4 (IP).
* VCAP_KF_ARP_OPCODE: W2, sparx5: is2/es2, lan966x: is2
* ARP opcode
* VCAP_KF_ARP_OPCODE_UNKNOWN_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if not one of the codes defined in VCAP_KF_ARP_OPCODE
* VCAP_KF_ARP_PROTO_SPACE_OK_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if protocol address space is 0x0800
* VCAP_KF_ARP_SENDER_MATCH_IS: W1, sparx5: is2/es2, lan966x: is2
* Sender Hardware Address = SMAC (ARP)
* VCAP_KF_ARP_TGT_MATCH_IS: W1, sparx5: is2/es2, lan966x: is2
* Target Hardware Address = SMAC (RARP)
* VCAP_KF_COSID_CLS: W3, sparx5: es0/es2
* Class of service
* VCAP_KF_ES0_ISDX_KEY_ENA: W1, sparx5: es2
* The value taken from the IFH .FWD.ES0_ISDX_KEY_ENA
* VCAP_KF_ETYPE: W16, sparx5: is0/is2/es2, lan966x: is1/is2
* Ethernet type
* VCAP_KF_ETYPE_LEN_IS: W1, sparx5: is0/is2/es2, lan966x: is1
* Set if frame has EtherType >= 0x600
* VCAP_KF_HOST_MATCH: W1, lan966x: is2
* The action from the SMAC_SIP4 or SMAC_SIP6 lookups. Used for IP source
* guarding.
* VCAP_KF_IF_EGR_PORT_MASK: W32, sparx5: es2
* Egress port mask, one bit per port
* VCAP_KF_IF_EGR_PORT_MASK_RNG: W3, sparx5: es2
* Select which 32 port group is available in IF_EGR_PORT (or virtual ports or
* CPU queue)
* VCAP_KF_IF_EGR_PORT_NO: sparx5 es0 W7, lan966x es0 W4
* Egress port number
* VCAP_KF_IF_IGR_PORT: sparx5 is0 W7, sparx5 es2 W9, lan966x is1 W3, lan966x
* is2 W4, lan966x es0 W4
* Sparx5: Logical ingress port number retrieved from
* ANA_CL::PORT_ID_CFG.LPORT_NUM or ERLEG, LAN966x: ingress port nunmber
* VCAP_KF_IF_IGR_PORT_MASK: sparx5 is0 W65, sparx5 is2 W32, sparx5 is2 W65,
* lan966x is1 W9, lan966x is2 W9
* Ingress port mask, one bit per port/erleg
* VCAP_KF_IF_IGR_PORT_MASK_L3: W1, sparx5: is2
* If set, IF_IGR_PORT_MASK, IF_IGR_PORT_MASK_RNG, and IF_IGR_PORT_MASK_SEL are
* used to specify L3 interfaces
* VCAP_KF_IF_IGR_PORT_MASK_RNG: W4, sparx5: is2
* Range selector for IF_IGR_PORT_MASK. Specifies which group of 32 ports are
* available in IF_IGR_PORT_MASK
* VCAP_KF_IF_IGR_PORT_MASK_SEL: W2, sparx5: is0/is2
* Mode selector for IF_IGR_PORT_MASK, applicable when IF_IGR_PORT_MASK_L3 == 0.
* Mapping: 0: DEFAULT 1: LOOPBACK 2: MASQUERADE 3: CPU_VD
* VCAP_KF_IF_IGR_PORT_SEL: W1, sparx5: es2
* Selector for IF_IGR_PORT: physical port number or ERLEG
* VCAP_KF_IP4_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2
* Set if frame has EtherType = 0x800 and IP version = 4
* VCAP_KF_IP_MC_IS: W1, sparx5: is0, lan966x: is1
* Set if frame is IPv4 frame and frame's destination MAC address is an IPv4
* multicast address (0x01005E0 /25). Set if frame is IPv6 frame and frame's
* destination MAC address is an IPv6 multicast address (0x3333/16).
* VCAP_KF_IP_PAYLOAD_5TUPLE: W32, sparx5: is0, lan966x: is1
* Payload bytes after IP header
* VCAP_KF_IP_PAYLOAD_S1_IP6: W112, lan966x: is1
* Payload after IPv6 header
* VCAP_KF_IP_SNAP_IS: W1, sparx5: is0, lan966x: is1
* Set if frame is IPv4, IPv6, or SNAP frame
* VCAP_KF_ISDX_CLS: sparx5 is2 W12, sparx5 es0 W12, sparx5 es2 W12, lan966x es0
* W8
* Classified ISDX
* VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2/es0/es2, lan966x: is2/es0
* Set if classified ISDX > 0
* VCAP_KF_L2_BC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2/es0
* Set if frame's destination MAC address is the broadcast address
* (FF-FF-FF-FF-FF-FF).
* VCAP_KF_L2_DMAC: W48, sparx5: is0/is2/es2, lan966x: is1/is2
* Destination MAC address
* VCAP_KF_L2_FRM_TYPE: W4, lan966x: is2
* Frame subtype for specific EtherTypes (MRP, DLR)
* VCAP_KF_L2_FWD_IS: W1, sparx5: is2
* Set if the frame is allowed to be forwarded to front ports
* VCAP_KF_L2_LLC: W40, lan966x: is2
* LLC header and data after up to two VLAN tags and the type/length field
* VCAP_KF_L2_MAC: W48, lan966x: is1
* MAC address (FIRST=1: SMAC, FIRST=0: DMAC)
* VCAP_KF_L2_MC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2/es0
* Set if frame's destination MAC address is a multicast address (bit 40 = 1).
* VCAP_KF_L2_PAYLOAD0: W16, lan966x: is2
* Payload bytes 0-1 after the frame's EtherType
* VCAP_KF_L2_PAYLOAD1: W8, lan966x: is2
* Payload byte 4 after the frame's EtherType. This is specifically for PTP
* frames.
* VCAP_KF_L2_PAYLOAD2: W3, lan966x: is2
* Bits 7, 2, and 1 from payload byte 6 after the frame's EtherType. This is
* specifically for PTP frames.
* VCAP_KF_L2_PAYLOAD_ETYPE: W64, sparx5: is2/es2
* Byte 0-7 of L2 payload after Type/Len field and overloading for OAM
* VCAP_KF_L2_SMAC: W48, sparx5: is0/is2/es2, lan966x: is1/is2
* Source MAC address
* VCAP_KF_L2_SNAP: W40, lan966x: is2
* SNAP header after LLC header (AA-AA-03)
* VCAP_KF_L3_DIP_EQ_SIP_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if Src IP matches Dst IP address
* VCAP_KF_L3_DPL_CLS: W1, sparx5: es0/es2, lan966x: es0
* The frames drop precedence level
* VCAP_KF_L3_DSCP: W6, sparx5: is0, lan966x: is1
* Frame's DSCP value
* VCAP_KF_L3_DST_IS: W1, sparx5: is2
* Set if lookup is done for egress router leg
* VCAP_KF_L3_FRAGMENT: W1, lan966x: is1/is2
* Set if IPv4 frame is fragmented
* VCAP_KF_L3_FRAGMENT_TYPE: W2, sparx5: is0/is2/es2
* L3 Fragmentation type (none, initial, suspicious, valid follow up)
* VCAP_KF_L3_FRAG_INVLD_L4_LEN: W1, sparx5: is0/is2
* Set if frame's L4 length is less than ANA_CL:COMMON:CLM_FRAGMENT_CFG.L4_MIN_L
* EN
* VCAP_KF_L3_FRAG_OFS_GT0: W1, lan966x: is1/is2
* Set if IPv4 frame is fragmented and it is not the first fragment
* VCAP_KF_L3_IP4_DIP: W32, sparx5: is0/is2/es2, lan966x: is1/is2
* Destination IPv4 Address
* VCAP_KF_L3_IP4_SIP: W32, sparx5: is0/is2/es2, lan966x: is1/is2
* Source IPv4 Address
* VCAP_KF_L3_IP6_DIP: sparx5 is0 W128, sparx5 is2 W128, sparx5 es2 W128,
* lan966x is1 W64, lan966x is1 W128, lan966x is2 W128
* Sparx5: Full IPv6 DIP, LAN966x: Either Full IPv6 DIP or a subset depending on
* frame type
* VCAP_KF_L3_IP6_DIP_MSB: W16, lan966x: is1
* MS 16bits of IPv6 DIP
* VCAP_KF_L3_IP6_SIP: sparx5 is0 W128, sparx5 is2 W128, sparx5 es2 W128,
* lan966x is1 W128, lan966x is1 W64, lan966x is2 W128
* Sparx5: Full IPv6 SIP, LAN966x: Either Full IPv6 SIP or a subset depending on
* frame type
* VCAP_KF_L3_IP6_SIP_MSB: W16, lan966x: is1
* MS 16bits of IPv6 DIP
* VCAP_KF_L3_IP_PROTO: W8, sparx5: is0/is2/es2, lan966x: is1/is2
* IPv4 frames: IP protocol. IPv6 frames: Next header, same as for IPV4
* VCAP_KF_L3_OPTIONS_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2
* Set if IPv4 frame contains options (IP len > 5)
* VCAP_KF_L3_PAYLOAD: sparx5 is2 W96, sparx5 is2 W40, sparx5 es2 W96, sparx5
* es2 W40, lan966x is2 W56
* Sparx5: Payload bytes after IP header. IPv4: IPv4 options are not parsed so
* payload is always taken 20 bytes after the start of the IPv4 header, LAN966x:
* Bytes 0-6 after IP header
* VCAP_KF_L3_RT_IS: W1, sparx5: is2/es2
* Set if frame has hit a router leg
* VCAP_KF_L3_TOS: W8, sparx5: is2/es2, lan966x: is2
* Sparx5: Frame's IPv4/IPv6 DSCP and ECN fields, LAN966x: IP TOS field
* VCAP_KF_L3_TTL_GT0: W1, sparx5: is2/es2, lan966x: is2
* Set if IPv4 TTL / IPv6 hop limit is greater than 0
* VCAP_KF_L4_1588_DOM: W8, lan966x: is2
* PTP over UDP: domainNumber
* VCAP_KF_L4_1588_VER: W4, lan966x: is2
* PTP over UDP: version
* VCAP_KF_L4_ACK: W1, sparx5: is2/es2, lan966x: is2
* Sparx5 and LAN966x: TCP flag ACK, LAN966x only: PTP over UDP: flagField bit 2
* (unicastFlag)
* VCAP_KF_L4_DPORT: W16, sparx5: is2/es2, lan966x: is2
* Sparx5: TCP/UDP destination port. Overloading for IP_7TUPLE: Non-TCP/UDP IP
* frames: L4_DPORT = L3_IP_PROTO, LAN966x: TCP/UDP destination port
* VCAP_KF_L4_FIN: W1, sparx5: is2/es2, lan966x: is2
* TCP flag FIN, LAN966x: TCP flag FIN, and for PTP over UDP: messageType bit 1
* VCAP_KF_L4_PAYLOAD: W64, sparx5: is2/es2
* Payload bytes after TCP/UDP header Overloading for IP_7TUPLE: Non TCP/UDP
* frames: Payload bytes 0-7 after IP header. IPv4 options are not parsed so
* payload is always taken 20 bytes after the start of the IPv4 header for non
* TCP/UDP IPv4 frames
* VCAP_KF_L4_PSH: W1, sparx5: is2/es2, lan966x: is2
* Sparx5: TCP flag PSH, LAN966x: TCP: TCP flag PSH. PTP over UDP: flagField bit
* 1 (twoStepFlag)
* VCAP_KF_L4_RNG: sparx5 is0 W8, sparx5 is2 W16, sparx5 es2 W16, lan966x is1
* W8, lan966x is2 W8
* Range checker bitmask (one for each range checker). Input into range checkers
* is taken from classified results (VID, DSCP) and frame (SPORT, DPORT, ETYPE,
* outer VID, inner VID)
* VCAP_KF_L4_RST: W1, sparx5: is2/es2, lan966x: is2
* Sparx5: TCP flag RST , LAN966x: TCP: TCP flag RST. PTP over UDP: messageType
* bit 3
* VCAP_KF_L4_SEQUENCE_EQ0_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if TCP sequence number is 0, LAN966x: Overlaid with PTP over UDP:
* messageType bit 0
* VCAP_KF_L4_SPORT: W16, sparx5: is0/is2/es2, lan966x: is1/is2
* TCP/UDP source port
* VCAP_KF_L4_SPORT_EQ_DPORT_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if UDP or TCP source port equals UDP or TCP destination port
* VCAP_KF_L4_SYN: W1, sparx5: is2/es2, lan966x: is2
* Sparx5: TCP flag SYN, LAN966x: TCP: TCP flag SYN. PTP over UDP: messageType
* bit 2
* VCAP_KF_L4_URG: W1, sparx5: is2/es2, lan966x: is2
* Sparx5: TCP flag URG, LAN966x: TCP: TCP flag URG. PTP over UDP: flagField bit
* 7 (reserved)
* VCAP_KF_LOOKUP_FIRST_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2
* Selects between entries relevant for first and second lookup. Set for first
* lookup, cleared for second lookup.
* VCAP_KF_LOOKUP_GEN_IDX: W12, sparx5: is0
* Generic index - for chaining CLM instances
* VCAP_KF_LOOKUP_GEN_IDX_SEL: W2, sparx5: is0
* Select the mode of the Generic Index
* VCAP_KF_LOOKUP_INDEX: W2, lan966x: is1
* 0: First lookup, 1: Second lookup, 2: Third lookup, Similar to VCAP_KF_FIRST
* but with extra info
* VCAP_KF_LOOKUP_PAG: W8, sparx5: is2, lan966x: is2
* Classified Policy Association Group: chains rules from IS1/CLM to IS2
* 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
* This is missing in the datasheet, but present in the OAM keyset in XML
* VCAP_KF_OAM_FLAGS: W8, lan966x: is2
* Frame's OAM flags
* VCAP_KF_OAM_MEL_FLAGS: W7, lan966x: is2
* Encoding of MD level/MEG level (MEL)
* VCAP_KF_OAM_MEPID: W16, lan966x: is2
* CCM frame's OAM MEP ID
* VCAP_KF_OAM_OPCODE: W8, lan966x: is2
* Frame's OAM opcode
* VCAP_KF_OAM_VER: W5, lan966x: is2
* Frame's OAM version
* VCAP_KF_OAM_Y1731_IS: W1, sparx5: is2/es2, lan966x: is2
* Set if frame's EtherType = 0x8902
* VCAP_KF_PDU_TYPE: W4, lan966x: es0
* PDU type value (none, OAM CCM, MRP, DLR, RTE, IPv4, IPv6, OAM non-CCM)
* VCAP_KF_PROT_ACTIVE: W1, sparx5: es0/es2
* Protection is active
* VCAP_KF_RTP_ID: W10, lan966x: es0
* Classified RTP_ID
* VCAP_KF_RT_FRMID: W32, lan966x: is1
* Profinet or OPC-UA FrameId
* VCAP_KF_RT_TYPE: W2, lan966x: is1
* Encoding of frame's EtherType: 0: Other, 1: Profinet, 2: OPC-UA, 3: Custom
* (ANA::RT_CUSTOM)
* VCAP_KF_RT_VLAN_IDX: W3, lan966x: is1
* Real-time VLAN index from ANA::RT_VLAN_PCP
* VCAP_KF_TCP_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2
* Set if frame is IPv4 TCP frame (IP protocol = 6) or IPv6 TCP frames (Next
* header = 6)
* VCAP_KF_TCP_UDP_IS: W1, sparx5: is0/is2/es2, lan966x: is1
* Set if frame is IPv4/IPv6 TCP or UDP frame (IP protocol/next header equals 6
* or 17)
* VCAP_KF_TYPE: sparx5 is0 W2, sparx5 is0 W1, sparx5 is2 W4, sparx5 is2 W2,
* sparx5 es0 W1, sparx5 es2 W3, lan966x is1 W1, lan966x is1 W2, lan966x is2 W4,
* lan966x is2 W2
* Keyset type id - set by the API
*/
/* Keyfield names */
enum vcap_key_field {
VCAP_KF_NO_VALUE, /* initial value */
VCAP_KF_8021BR_ECID_BASE,
VCAP_KF_8021BR_ECID_EXT,
VCAP_KF_8021BR_E_TAGGED,
VCAP_KF_8021BR_GRP,
VCAP_KF_8021BR_IGR_ECID_BASE,
VCAP_KF_8021BR_IGR_ECID_EXT,
VCAP_KF_8021CB_R_TAGGED_IS,
VCAP_KF_8021Q_DEI0,
VCAP_KF_8021Q_DEI1,
VCAP_KF_8021Q_DEI2,
VCAP_KF_8021Q_DEI_CLS,
VCAP_KF_8021Q_PCP0,
VCAP_KF_8021Q_PCP1,
VCAP_KF_8021Q_PCP2,
VCAP_KF_8021Q_PCP_CLS,
VCAP_KF_8021Q_TPID,
VCAP_KF_8021Q_TPID0,
VCAP_KF_8021Q_TPID1,
VCAP_KF_8021Q_TPID2,
VCAP_KF_8021Q_VID0,
VCAP_KF_8021Q_VID1,
VCAP_KF_8021Q_VID2,
VCAP_KF_8021Q_VID_CLS,
VCAP_KF_8021Q_VLAN_DBL_TAGGED_IS,
VCAP_KF_8021Q_VLAN_TAGGED_IS,
VCAP_KF_8021Q_VLAN_TAGS,
VCAP_KF_ACL_GRP_ID,
VCAP_KF_ARP_ADDR_SPACE_OK_IS,
VCAP_KF_ARP_LEN_OK_IS,
VCAP_KF_ARP_OPCODE,
VCAP_KF_ARP_OPCODE_UNKNOWN_IS,
VCAP_KF_ARP_PROTO_SPACE_OK_IS,
VCAP_KF_ARP_SENDER_MATCH_IS,
VCAP_KF_ARP_TGT_MATCH_IS,
VCAP_KF_COSID_CLS,
VCAP_KF_ES0_ISDX_KEY_ENA,
VCAP_KF_ETYPE,
VCAP_KF_ETYPE_LEN_IS,
VCAP_KF_HOST_MATCH,
VCAP_KF_IF_EGR_PORT_MASK,
VCAP_KF_IF_EGR_PORT_MASK_RNG,
VCAP_KF_IF_EGR_PORT_NO,
VCAP_KF_IF_IGR_PORT,
VCAP_KF_IF_IGR_PORT_MASK,
VCAP_KF_IF_IGR_PORT_MASK_L3,
VCAP_KF_IF_IGR_PORT_MASK_RNG,
VCAP_KF_IF_IGR_PORT_MASK_SEL,
VCAP_KF_IF_IGR_PORT_SEL,
VCAP_KF_IP4_IS,
VCAP_KF_IP_MC_IS,
VCAP_KF_IP_PAYLOAD_5TUPLE,
VCAP_KF_IP_PAYLOAD_S1_IP6,
VCAP_KF_IP_SNAP_IS,
VCAP_KF_ISDX_CLS,
VCAP_KF_ISDX_GT0_IS,
VCAP_KF_L2_BC_IS,
VCAP_KF_L2_DMAC,
VCAP_KF_L2_FRM_TYPE,
VCAP_KF_L2_FWD_IS,
VCAP_KF_L2_LLC,
VCAP_KF_L2_MAC,
VCAP_KF_L2_MC_IS,
VCAP_KF_L2_PAYLOAD0,
VCAP_KF_L2_PAYLOAD1,
VCAP_KF_L2_PAYLOAD2,
VCAP_KF_L2_PAYLOAD_ETYPE,
VCAP_KF_L2_SMAC,
VCAP_KF_L2_SNAP,
VCAP_KF_L3_DIP_EQ_SIP_IS,
VCAP_KF_L3_DPL_CLS,
VCAP_KF_L3_DSCP,
VCAP_KF_L3_DST_IS,
VCAP_KF_L3_FRAGMENT,
VCAP_KF_L3_FRAGMENT_TYPE,
VCAP_KF_L3_FRAG_INVLD_L4_LEN,
VCAP_KF_L3_FRAG_OFS_GT0,
VCAP_KF_L3_IP4_DIP,
VCAP_KF_L3_IP4_SIP,
VCAP_KF_L3_IP6_DIP,
VCAP_KF_L3_IP6_DIP_MSB,
VCAP_KF_L3_IP6_SIP,
VCAP_KF_L3_IP6_SIP_MSB,
VCAP_KF_L3_IP_PROTO,
VCAP_KF_L3_OPTIONS_IS,
VCAP_KF_L3_PAYLOAD,
VCAP_KF_L3_RT_IS,
VCAP_KF_L3_TOS,
VCAP_KF_L3_TTL_GT0,
VCAP_KF_L4_1588_DOM,
VCAP_KF_L4_1588_VER,
VCAP_KF_L4_ACK,
VCAP_KF_L4_DPORT,
VCAP_KF_L4_FIN,
VCAP_KF_L4_PAYLOAD,
VCAP_KF_L4_PSH,
VCAP_KF_L4_RNG,
VCAP_KF_L4_RST,
VCAP_KF_L4_SEQUENCE_EQ0_IS,
VCAP_KF_L4_SPORT,
VCAP_KF_L4_SPORT_EQ_DPORT_IS,
VCAP_KF_L4_SYN,
VCAP_KF_L4_URG,
VCAP_KF_LOOKUP_FIRST_IS,
VCAP_KF_LOOKUP_GEN_IDX,
VCAP_KF_LOOKUP_GEN_IDX_SEL,
VCAP_KF_LOOKUP_INDEX,
VCAP_KF_LOOKUP_PAG,
VCAP_KF_MIRROR_PROBE,
VCAP_KF_OAM_CCM_CNTS_EQ0,
VCAP_KF_OAM_DETECTED,
VCAP_KF_OAM_FLAGS,
VCAP_KF_OAM_MEL_FLAGS,
VCAP_KF_OAM_MEPID,
VCAP_KF_OAM_OPCODE,
VCAP_KF_OAM_VER,
VCAP_KF_OAM_Y1731_IS,
VCAP_KF_PDU_TYPE,
VCAP_KF_PROT_ACTIVE,
VCAP_KF_RTP_ID,
VCAP_KF_RT_FRMID,
VCAP_KF_RT_TYPE,
VCAP_KF_RT_VLAN_IDX,
VCAP_KF_TCP_IS,
VCAP_KF_TCP_UDP_IS,
VCAP_KF_TYPE,
};
/* Actionset names with origin information */
enum vcap_actionfield_set {
VCAP_AFS_NO_VALUE, /* initial value */
VCAP_AFS_BASE_TYPE, /* sparx5 is2 X3, sparx5 es2 X3, lan966x is2 X2 */
VCAP_AFS_CLASSIFICATION, /* sparx5 is0 X2 */
VCAP_AFS_CLASS_REDUCED, /* sparx5 is0 X1 */
VCAP_AFS_ES0, /* sparx5 es0 X1 */
VCAP_AFS_FULL, /* sparx5 is0 X3 */
VCAP_AFS_S1, /* lan966x is1 X1 */
VCAP_AFS_SMAC_SIP, /* lan966x is2 X1 */
VCAP_AFS_VID, /* lan966x es0 X1 */
};
/* List of actionfields with description
*
* VCAP_AF_ACL_ID: W6, lan966x: is2
* Logical ID for the entry. This ID is extracted together with the frame in the
* CPU extraction header. Only applicable to actions with CPU_COPY_ENA or
* HIT_ME_ONCE set.
* VCAP_AF_CLS_VID_SEL: W3, sparx5: is0
* Controls the classified VID: 0: VID_NONE: No action. 1: VID_ADD: New VID =
* old VID + VID_VAL. 2: VID_REPLACE: New VID = VID_VAL. 3: VID_FIRST_TAG: New
* VID = VID from frame's first tag (outer tag) if available, otherwise VID_VAL.
* 4: VID_SECOND_TAG: New VID = VID from frame's second tag (middle tag) if
* available, otherwise VID_VAL. 5: VID_THIRD_TAG: New VID = VID from frame's
* third tag (inner tag) if available, otherwise VID_VAL.
* VCAP_AF_CNT_ID: sparx5 is2 W12, sparx5 es2 W11
* Counter ID, used per lookup to index the 4K frame counters (ANA_ACL:CNT_TBL).
* Multiple VCAP IS2 entries can use the same counter.
* VCAP_AF_COPY_PORT_NUM: W7, sparx5: es2
* QSYS port number when FWD_MODE is redirect or copy
* VCAP_AF_COPY_QUEUE_NUM: W16, sparx5: es2
* QSYS queue number when FWD_MODE is redirect or copy
* VCAP_AF_CPU_COPY_ENA: W1, sparx5: is2/es2, lan966x: is2
* Setting this bit to 1 causes all frames that hit this action to be copied to
* the CPU extraction queue specified in CPU_QUEUE_NUM.
* VCAP_AF_CPU_QU: W3, sparx5: es0
* CPU extraction queue. Used when FWD_SEL >0 and PIPELINE_ACT = XTR.
* VCAP_AF_CPU_QUEUE_NUM: W3, sparx5: is2/es2, lan966x: is2
* CPU queue number. Used when CPU_COPY_ENA is set.
* VCAP_AF_CUSTOM_ACE_TYPE_ENA: W4, lan966x: is1
* Enables use of custom keys in IS2. Bits 3:2 control second lookup in IS2
* while bits 1:0 control first lookup. Encoding per lookup: 0: Disabled. 1:
* Extract 40 bytes after position corresponding to the location of the IPv4
* header and use as key. 2: Extract 40 bytes after SMAC and use as key
* VCAP_AF_DEI_A_VAL: W1, sparx5: es0, lan966x: es0
* DEI used in ES0 tag A. See TAG_A_DEI_SEL.
* VCAP_AF_DEI_B_VAL: W1, sparx5: es0, lan966x: es0
* DEI used in ES0 tag B. See TAG_B_DEI_SEL.
* VCAP_AF_DEI_C_VAL: W1, sparx5: es0
* DEI used in ES0 tag C. See TAG_C_DEI_SEL.
* VCAP_AF_DEI_ENA: W1, sparx5: is0, lan966x: is1
* If set, use DEI_VAL as classified DEI value. Otherwise, DEI from basic
* classification is used
* VCAP_AF_DEI_VAL: W1, sparx5: is0, lan966x: is1
* See DEI_ENA
* VCAP_AF_DLR_SEL: W2, lan966x: is1
* 0: No changes to port-based selection in ANA:PORT:OAM_CFG.DLR_ENA. 1: Enable
* DLR frame processing 2: Disable DLR processing
* VCAP_AF_DP_ENA: W1, sparx5: is0, lan966x: is1
* If set, use DP_VAL as classified drop precedence level. Otherwise, drop
* precedence level from basic classification is used.
* VCAP_AF_DP_VAL: sparx5 is0 W2, lan966x is1 W1
* See DP_ENA.
* VCAP_AF_DSCP_ENA: W1, sparx5: is0, lan966x: is1
* If set, use DSCP_VAL as classified DSCP value. Otherwise, DSCP value from
* basic classification is used.
* VCAP_AF_DSCP_SEL: W3, sparx5: es0
* Selects source for DSCP. 0: Controlled by port configuration and IFH. 1:
* Classified DSCP via IFH. 2: DSCP_VAL. 3: Reserved. 4: Mapped using mapping
* table 0, otherwise use DSCP_VAL. 5: Mapped using mapping table 1, otherwise
* use mapping table 0. 6: Mapped using mapping table 2, otherwise use DSCP_VAL.
* 7: Mapped using mapping table 3, otherwise use mapping table 2
* VCAP_AF_DSCP_VAL: W6, sparx5: is0/es0, lan966x: is1
* See DSCP_ENA.
* VCAP_AF_ES2_REW_CMD: W3, sparx5: es2
* Command forwarded to REW: 0: No action. 1: SWAP MAC addresses. 2: Do L2CP
* DMAC translation when entering or leaving a tunnel.
* VCAP_AF_ESDX: sparx5 es0 W13, lan966x es0 W8
* Egress counter index. Used to index egress counter set as defined in
* REW::STAT_CFG.
* VCAP_AF_FWD_KILL_ENA: W1, lan966x: is2
* Setting this bit to 1 denies forwarding of the frame forwarding to any front
* port. The frame can still be copied to the CPU by other actions.
* VCAP_AF_FWD_MODE: W2, sparx5: es2
* Forward selector: 0: Forward. 1: Discard. 2: Redirect. 3: Copy.
* VCAP_AF_FWD_SEL: W2, sparx5: es0
* ES0 Forward selector. 0: No action. 1: Copy to loopback interface. 2:
* Redirect to loopback interface. 3: Discard
* VCAP_AF_HIT_ME_ONCE: W1, sparx5: is2/es2, lan966x: is2
* Setting this bit to 1 causes the first frame that hits this action where the
* HIT_CNT counter is zero to be copied to the CPU extraction queue specified in
* CPU_QUEUE_NUM. The HIT_CNT counter is then incremented and any frames that
* hit this action later are not copied to the CPU. To re-enable the HIT_ME_ONCE
* functionality, the HIT_CNT counter must be cleared.
* VCAP_AF_HOST_MATCH: W1, lan966x: is2
* Used for IP source guarding. If set, it signals that the host is a valid (for
* instance a valid combination of source MAC address and source IP address).
* HOST_MATCH is input to the IS2 keys.
* VCAP_AF_IGNORE_PIPELINE_CTRL: W1, sparx5: is2/es2
* Ignore ingress pipeline control. This enforces the use of the VCAP IS2 action
* even when the pipeline control has terminated the frame before VCAP IS2.
* VCAP_AF_INTR_ENA: W1, sparx5: is2/es2
* If set, an interrupt is triggered when this rule is hit
* VCAP_AF_ISDX_ADD_REPLACE_SEL: W1, sparx5: is0
* Controls the classified ISDX. 0: New ISDX = old ISDX + ISDX_VAL. 1: New ISDX
* = ISDX_VAL.
* VCAP_AF_ISDX_ADD_VAL: W8, lan966x: is1
* If ISDX_REPLACE_ENA is set, ISDX_ADD_VAL is used directly as the new ISDX.
* Encoding: ISDX_REPLACE_ENA=0, ISDX_ADD_VAL=0: Disabled ISDX_EPLACE_ENA=0,
* ISDX_ADD_VAL>0: Add value to classified ISDX. ISDX_REPLACE_ENA=1: Replace
* with ISDX_ADD_VAL value.
* VCAP_AF_ISDX_ENA: W1, lan966x: is2
* Setting this bit to 1 causes the classified ISDX to be set to the value of
* POLICE_IDX[8:0].
* VCAP_AF_ISDX_REPLACE_ENA: W1, lan966x: is1
* If set, classified ISDX is set to ISDX_ADD_VAL.
* VCAP_AF_ISDX_VAL: W12, sparx5: is0
* See isdx_add_replace_sel
* VCAP_AF_LOOP_ENA: W1, sparx5: es0
* 0: Forward based on PIPELINE_PT and FWD_SEL
* VCAP_AF_LRN_DIS: W1, sparx5: is2, lan966x: is2
* Setting this bit to 1 disables learning of frames hitting this action.
* VCAP_AF_MAP_IDX: W9, sparx5: is0
* Index for QoS mapping table lookup
* VCAP_AF_MAP_KEY: W3, sparx5: is0
* Key type for QoS mapping table lookup. 0: DEI0, PCP0 (outer tag). 1: DEI1,
* PCP1 (middle tag). 2: DEI2, PCP2 (inner tag). 3: MPLS TC. 4: PCP0 (outer
* tag). 5: E-DEI, E-PCP (E-TAG). 6: DSCP if available, otherwise none. 7: DSCP
* if available, otherwise DEI0, PCP0 (outer tag) if available using MAP_IDX+8,
* otherwise none
* VCAP_AF_MAP_LOOKUP_SEL: W2, sparx5: is0
* Selects which of the two QoS Mapping Table lookups that MAP_KEY and MAP_IDX
* are applied to. 0: No changes to the QoS Mapping Table lookup. 1: Update key
* type and index for QoS Mapping Table lookup #0. 2: Update key type and index
* for QoS Mapping Table lookup #1. 3: Reserved.
* VCAP_AF_MASK_MODE: sparx5 is0 W3, sparx5 is2 W3, lan966x is2 W2
* Controls the PORT_MASK use. Sparx5: 0: OR_DSTMASK, 1: AND_VLANMASK, 2:
* REPLACE_PGID, 3: REPLACE_ALL, 4: REDIR_PGID, 5: OR_PGID_MASK, 6: VSTAX, 7:
* Not applicable. LAN966X: 0: No action, 1: Permit/deny (AND), 2: Policy
* forwarding (DMAC lookup), 3: Redirect. The CPU port is untouched by
* MASK_MODE.
* VCAP_AF_MATCH_ID: W16, sparx5: is2
* Logical ID for the entry. The MATCH_ID is extracted together with the frame
* if the frame is forwarded to the CPU (CPU_COPY_ENA). The result is placed in
* IFH.CL_RSLT.
* VCAP_AF_MATCH_ID_MASK: W16, sparx5: is2
* Mask used by MATCH_ID.
* VCAP_AF_MIRROR_ENA: W1, lan966x: is2
* Setting this bit to 1 causes frames to be mirrored to the mirror target port
* (ANA::MIRRPORPORTS).
* VCAP_AF_MIRROR_PROBE: W2, sparx5: is2
* Mirroring performed according to configuration of a mirror probe. 0: No
* mirroring. 1: Mirror probe 0. 2: Mirror probe 1. 3: Mirror probe 2
* VCAP_AF_MIRROR_PROBE_ID: W2, sparx5: es2
* Signals a mirror probe to be placed in the IFH. Only possible when FWD_MODE
* is copy. 0: No mirroring. 1-3: Use mirror probe 0-2.
* VCAP_AF_MRP_SEL: W2, lan966x: is1
* 0: No changes to port-based selection in ANA:PORT:OAM_CFG.MRP_ENA. 1: Enable
* MRP frame processing 2: Disable MRP processing
* VCAP_AF_NXT_IDX: W12, sparx5: is0
* Index used as part of key (field G_IDX) in the next lookup.
* VCAP_AF_NXT_IDX_CTRL: W3, sparx5: is0
* Controls the generation of the G_IDX used in the VCAP CLM next lookup
* VCAP_AF_OAM_SEL: W3, lan966x: is1
* 0: No changes to port-based selection in ANA:PORT:OAM_CFG.OAM_CFG 1: Enable
* OAM frame processing for untagged frames 2: Enable OAM frame processing for
* single frames 3: Enable OAM frame processing for double frames 4: Disable OAM
* frame processing
* VCAP_AF_PAG_OVERRIDE_MASK: W8, sparx5: is0, lan966x: is1
* Bits set in this mask will override PAG_VAL from port profile. New PAG = (PAG
* (input) AND ~PAG_OVERRIDE_MASK) OR (PAG_VAL AND PAG_OVERRIDE_MASK)
* VCAP_AF_PAG_VAL: W8, sparx5: is0, lan966x: is1
* See PAG_OVERRIDE_MASK.
* VCAP_AF_PCP_A_VAL: W3, sparx5: es0, lan966x: es0
* PCP used in ES0 tag A. See TAG_A_PCP_SEL.
* VCAP_AF_PCP_B_VAL: W3, sparx5: es0, lan966x: es0
* PCP used in ES0 tag B. See TAG_B_PCP_SEL.
* VCAP_AF_PCP_C_VAL: W3, sparx5: es0
* PCP used in ES0 tag C. See TAG_C_PCP_SEL.
* VCAP_AF_PCP_ENA: W1, sparx5: is0, lan966x: is1
* If set, use PCP_VAL as classified PCP value. Otherwise, PCP from basic
* classification is used.
* VCAP_AF_PCP_VAL: W3, sparx5: is0, lan966x: is1
* See PCP_ENA.
* VCAP_AF_PIPELINE_ACT: W1, sparx5: es0
* Pipeline action when FWD_SEL > 0. 0: XTR. CPU_QU selects CPU extraction queue
* 1: LBK_ASM.
* VCAP_AF_PIPELINE_FORCE_ENA: W1, sparx5: is2
* If set, use PIPELINE_PT unconditionally and set PIPELINE_ACT = NONE if
* PIPELINE_PT == NONE. Overrules previous settings of pipeline point.
* VCAP_AF_PIPELINE_PT: sparx5 is2 W5, sparx5 es0 W2
* Pipeline point used if PIPELINE_FORCE_ENA is set
* VCAP_AF_POLICE_ENA: W1, sparx5: is2/es2, lan966x: is1/is2
* If set, POLICE_IDX is used to lookup ANA::POL.
* VCAP_AF_POLICE_IDX: sparx5 is2 W6, sparx5 es2 W6, lan966x is1 W9, lan966x is2
* W9
* Policer index.
* VCAP_AF_POLICE_REMARK: W1, sparx5: es2
* If set, frames exceeding policer rates are marked as yellow but not
* discarded.
* VCAP_AF_POLICE_VCAP_ONLY: W1, lan966x: is2
* Disable policing from QoS, and port policers. Only the VCAP policer selected
* by POLICE_IDX is active. Only applies to the second lookup.
* VCAP_AF_POP_VAL: W2, sparx5: es0
* Controls popping of Q-tags. The final number of Q-tags popped is calculated
* as shown in section 4.28.7.2 VLAN Pop Decision.
* VCAP_AF_PORT_MASK: sparx5 is0 W65, sparx5 is2 W68, lan966x is2 W8
* Port mask applied to the forwarding decision based on MASK_MODE.
* VCAP_AF_PUSH_CUSTOMER_TAG: W2, sparx5: es0
* Selects tag C mode: 0: Do not push tag C. 1: Push tag C if
* IFH.VSTAX.TAG.WAS_TAGGED = 1. 2: Push tag C if IFH.VSTAX.TAG.WAS_TAGGED = 0.
* 3: Push tag C if UNTAG_VID_ENA = 0 or (C-TAG.VID ! = VID_C_VAL).
* VCAP_AF_PUSH_INNER_TAG: W1, sparx5: es0, lan966x: es0
* Controls inner tagging. 0: Do not push ES0 tag B as inner tag. 1: Push ES0
* tag B as inner tag.
* VCAP_AF_PUSH_OUTER_TAG: W2, sparx5: es0, lan966x: es0
* Controls outer tagging. 0: No ES0 tag A: Port tag is allowed if enabled on
* port. 1: ES0 tag A: Push ES0 tag A. No port tag. 2: Force port tag: Always
* push port tag. No ES0 tag A. 3: Force untag: Never push port tag or ES0 tag
* A.
* VCAP_AF_QOS_ENA: W1, sparx5: is0, lan966x: is1
* If set, use QOS_VAL as classified QoS class. Otherwise, QoS class from basic
* classification is used.
* VCAP_AF_QOS_VAL: W3, sparx5: is0, lan966x: is1
* See QOS_ENA.
* VCAP_AF_REW_OP: W16, lan966x: is2
* Rewriter operation command.
* VCAP_AF_RT_DIS: W1, sparx5: is2
* If set, routing is disallowed. Only applies when IS_INNER_ACL is 0. See also
* IGR_ACL_ENA, EGR_ACL_ENA, and RLEG_STAT_IDX.
* VCAP_AF_SFID_ENA: W1, lan966x: is1
* If set, SFID_VAL is used to lookup ANA::SFID.
* VCAP_AF_SFID_VAL: W8, lan966x: is1
* Stream filter identifier.
* VCAP_AF_SGID_ENA: W1, lan966x: is1
* If set, SGID_VAL is used to lookup ANA::SGID.
* VCAP_AF_SGID_VAL: W8, lan966x: is1
* Stream gate identifier.
* VCAP_AF_SWAP_MACS_ENA: W1, sparx5: es0
* This setting is only active when FWD_SEL = 1 or FWD_SEL = 2 and PIPELINE_ACT
* = LBK_ASM. 0: No action. 1: Swap MACs and clear bit 40 in new SMAC.
* VCAP_AF_TAG_A_DEI_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects PCP for ES0 tag A. 0: Classified DEI. 1: DEI_A_VAL. 2: DP and QoS
* mapped to PCP (per port table). 3: DP.
* VCAP_AF_TAG_A_PCP_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects PCP for ES0 tag A. 0: Classified PCP. 1: PCP_A_VAL. 2: DP and QoS
* mapped to PCP (per port table). 3: QoS class.
* VCAP_AF_TAG_A_TPID_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects TPID for ES0 tag A: 0: 0x8100. 1: 0x88A8. 2: Custom
* (REW:PORT:PORT_VLAN_CFG.PORT_TPID). 3: If IFH.TAG_TYPE = 0 then 0x8100 else
* custom.
* VCAP_AF_TAG_A_VID_SEL: sparx5 es0 W2, lan966x es0 W1
* Selects VID for ES0 tag A. 0: Classified VID + VID_A_VAL. 1: VID_A_VAL.
* VCAP_AF_TAG_B_DEI_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects PCP for ES0 tag B. 0: Classified DEI. 1: DEI_B_VAL. 2: DP and QoS
* mapped to PCP (per port table). 3: DP.
* VCAP_AF_TAG_B_PCP_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects PCP for ES0 tag B. 0: Classified PCP. 1: PCP_B_VAL. 2: DP and QoS
* mapped to PCP (per port table). 3: QoS class.
* VCAP_AF_TAG_B_TPID_SEL: sparx5 es0 W3, lan966x es0 W2
* Selects TPID for ES0 tag B. 0: 0x8100. 1: 0x88A8. 2: Custom
* (REW:PORT:PORT_VLAN_CFG.PORT_TPID). 3: If IFH.TAG_TYPE = 0 then 0x8100 else
* custom.
* VCAP_AF_TAG_B_VID_SEL: sparx5 es0 W2, lan966x es0 W1
* Selects VID for ES0 tag B. 0: Classified VID + VID_B_VAL. 1: VID_B_VAL.
* VCAP_AF_TAG_C_DEI_SEL: W3, sparx5: es0
* Selects DEI source for ES0 tag C. 0: Classified DEI. 1: DEI_C_VAL. 2:
* REW::DP_MAP.DP [IFH.VSTAX.QOS.DP]. 3: DEI of popped VLAN tag if available
* (IFH.VSTAX.TAG.WAS_TAGGED = 1 and tot_pop_cnt>0) else DEI_C_VAL. 4: Mapped
* using mapping table 0, otherwise use DEI_C_VAL. 5: Mapped using mapping table
* 1, otherwise use mapping table 0. 6: Mapped using mapping table 2, otherwise
* use DEI_C_VAL. 7: Mapped using mapping table 3, otherwise use mapping table
* 2.
* VCAP_AF_TAG_C_PCP_SEL: W3, sparx5: es0
* Selects PCP source for ES0 tag C. 0: Classified PCP. 1: PCP_C_VAL. 2:
* Reserved. 3: PCP of popped VLAN tag if available (IFH.VSTAX.TAG.WAS_TAGGED=1
* and tot_pop_cnt>0) else PCP_C_VAL. 4: Mapped using mapping table 0, otherwise
* use PCP_C_VAL. 5: Mapped using mapping table 1, otherwise use mapping table
* 0. 6: Mapped using mapping table 2, otherwise use PCP_C_VAL. 7: Mapped using
* mapping table 3, otherwise use mapping table 2.
* VCAP_AF_TAG_C_TPID_SEL: W3, sparx5: es0
* Selects TPID for ES0 tag C. 0: 0x8100. 1: 0x88A8. 2: Custom 1. 3: Custom 2.
* 4: Custom 3. 5: See TAG_A_TPID_SEL.
* VCAP_AF_TAG_C_VID_SEL: W2, sparx5: es0
* Selects VID for ES0 tag C. The resulting VID is termed C-TAG.VID. 0:
* Classified VID. 1: VID_C_VAL. 2: IFH.ENCAP.GVID. 3: Reserved.
* VCAP_AF_TYPE: W1, sparx5: is0, lan966x: is1
* Actionset type id - Set by the API
* VCAP_AF_UNTAG_VID_ENA: W1, sparx5: es0
* Controls insertion of tag C. Untag or insert mode can be selected. See
* PUSH_CUSTOMER_TAG.
* VCAP_AF_VID_A_VAL: W12, sparx5: es0, lan966x: es0
* VID used in ES0 tag A. See TAG_A_VID_SEL.
* VCAP_AF_VID_B_VAL: W12, sparx5: es0, lan966x: es0
* VID used in ES0 tag B. See TAG_B_VID_SEL.
* VCAP_AF_VID_C_VAL: W12, sparx5: es0
* VID used in ES0 tag C. See TAG_C_VID_SEL.
* VCAP_AF_VID_REPLACE_ENA: W1, lan966x: is1
* Controls the classified VID: VID_REPLACE_ENA=0: Add VID_ADD_VAL to basic
* classified VID and use result as new classified VID. VID_REPLACE_ENA = 1:
* Replace basic classified VID with VID_VAL value and use as new classified
* VID.
* VCAP_AF_VID_VAL: sparx5 is0 W13, lan966x is1 W12
* New VID Value
* VCAP_AF_VLAN_POP_CNT: W2, lan966x: is1
* See VLAN_POP_CNT_ENA
* VCAP_AF_VLAN_POP_CNT_ENA: W1, lan966x: is1
* If set, use VLAN_POP_CNT as the number of VLAN tags to pop from the incoming
* frame. This number is used by the Rewriter. Otherwise, VLAN_POP_CNT from
* ANA:PORT:VLAN_CFG.VLAN_POP_CNT is used
*/
/* Actionfield names */
enum vcap_action_field {
VCAP_AF_NO_VALUE, /* initial value */
VCAP_AF_ACL_ID,
VCAP_AF_CLS_VID_SEL,
VCAP_AF_CNT_ID,
VCAP_AF_COPY_PORT_NUM,
VCAP_AF_COPY_QUEUE_NUM,
VCAP_AF_CPU_COPY_ENA,
VCAP_AF_CPU_QU,
VCAP_AF_CPU_QUEUE_NUM,
VCAP_AF_CUSTOM_ACE_TYPE_ENA,
VCAP_AF_DEI_A_VAL,
VCAP_AF_DEI_B_VAL,
VCAP_AF_DEI_C_VAL,
VCAP_AF_DEI_ENA,
VCAP_AF_DEI_VAL,
VCAP_AF_DLR_SEL,
VCAP_AF_DP_ENA,
VCAP_AF_DP_VAL,
VCAP_AF_DSCP_ENA,
VCAP_AF_DSCP_SEL,
VCAP_AF_DSCP_VAL,
VCAP_AF_ES2_REW_CMD,
VCAP_AF_ESDX,
VCAP_AF_FWD_KILL_ENA,
VCAP_AF_FWD_MODE,
VCAP_AF_FWD_SEL,
VCAP_AF_HIT_ME_ONCE,
VCAP_AF_HOST_MATCH,
VCAP_AF_IGNORE_PIPELINE_CTRL,
VCAP_AF_INTR_ENA,
VCAP_AF_ISDX_ADD_REPLACE_SEL,
VCAP_AF_ISDX_ADD_VAL,
VCAP_AF_ISDX_ENA,
VCAP_AF_ISDX_REPLACE_ENA,
VCAP_AF_ISDX_VAL,
VCAP_AF_LOOP_ENA,
VCAP_AF_LRN_DIS,
VCAP_AF_MAP_IDX,
VCAP_AF_MAP_KEY,
VCAP_AF_MAP_LOOKUP_SEL,
VCAP_AF_MASK_MODE,
VCAP_AF_MATCH_ID,
VCAP_AF_MATCH_ID_MASK,
VCAP_AF_MIRROR_ENA,
VCAP_AF_MIRROR_PROBE,
VCAP_AF_MIRROR_PROBE_ID,
VCAP_AF_MRP_SEL,
VCAP_AF_NXT_IDX,
VCAP_AF_NXT_IDX_CTRL,
VCAP_AF_OAM_SEL,
VCAP_AF_PAG_OVERRIDE_MASK,
VCAP_AF_PAG_VAL,
VCAP_AF_PCP_A_VAL,
VCAP_AF_PCP_B_VAL,
VCAP_AF_PCP_C_VAL,
VCAP_AF_PCP_ENA,
VCAP_AF_PCP_VAL,
VCAP_AF_PIPELINE_ACT,
VCAP_AF_PIPELINE_FORCE_ENA,
VCAP_AF_PIPELINE_PT,
VCAP_AF_POLICE_ENA,
VCAP_AF_POLICE_IDX,
VCAP_AF_POLICE_REMARK,
VCAP_AF_POLICE_VCAP_ONLY,
VCAP_AF_POP_VAL,
VCAP_AF_PORT_MASK,
VCAP_AF_PUSH_CUSTOMER_TAG,
VCAP_AF_PUSH_INNER_TAG,
VCAP_AF_PUSH_OUTER_TAG,
VCAP_AF_QOS_ENA,
VCAP_AF_QOS_VAL,
VCAP_AF_REW_OP,
VCAP_AF_RT_DIS,
VCAP_AF_SFID_ENA,
VCAP_AF_SFID_VAL,
VCAP_AF_SGID_ENA,
VCAP_AF_SGID_VAL,
VCAP_AF_SWAP_MACS_ENA,
VCAP_AF_TAG_A_DEI_SEL,
VCAP_AF_TAG_A_PCP_SEL,
VCAP_AF_TAG_A_TPID_SEL,
VCAP_AF_TAG_A_VID_SEL,
VCAP_AF_TAG_B_DEI_SEL,
VCAP_AF_TAG_B_PCP_SEL,
VCAP_AF_TAG_B_TPID_SEL,
VCAP_AF_TAG_B_VID_SEL,
VCAP_AF_TAG_C_DEI_SEL,
VCAP_AF_TAG_C_PCP_SEL,
VCAP_AF_TAG_C_TPID_SEL,
VCAP_AF_TAG_C_VID_SEL,
VCAP_AF_TYPE,
VCAP_AF_UNTAG_VID_ENA,
VCAP_AF_VID_A_VAL,
VCAP_AF_VID_B_VAL,
VCAP_AF_VID_C_VAL,
VCAP_AF_VID_REPLACE_ENA,
VCAP_AF_VID_VAL,
VCAP_AF_VLAN_POP_CNT,
VCAP_AF_VLAN_POP_CNT_ENA,
};
#endif /* __VCAP_AG_API__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,281 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API__
#define __VCAP_API__
#include <linux/types.h>
#include <linux/list.h>
#include <linux/netdevice.h>
/* Use the generated API model */
#include "vcap_ag_api.h"
#define VCAP_CID_LOOKUP_SIZE 100000 /* Chains in a lookup */
#define VCAP_CID_INGRESS_L0 1000000 /* Ingress Stage 1 Lookup 0 */
#define VCAP_CID_INGRESS_L1 1100000 /* Ingress Stage 1 Lookup 1 */
#define VCAP_CID_INGRESS_L2 1200000 /* Ingress Stage 1 Lookup 2 */
#define VCAP_CID_INGRESS_L3 1300000 /* Ingress Stage 1 Lookup 3 */
#define VCAP_CID_INGRESS_L4 1400000 /* Ingress Stage 1 Lookup 4 */
#define VCAP_CID_INGRESS_L5 1500000 /* Ingress Stage 1 Lookup 5 */
#define VCAP_CID_PREROUTING_IPV6 3000000 /* Prerouting Stage */
#define VCAP_CID_PREROUTING 6000000 /* Prerouting Stage */
#define VCAP_CID_INGRESS_STAGE2_L0 8000000 /* Ingress Stage 2 Lookup 0 */
#define VCAP_CID_INGRESS_STAGE2_L1 8100000 /* Ingress Stage 2 Lookup 1 */
#define VCAP_CID_INGRESS_STAGE2_L2 8200000 /* Ingress Stage 2 Lookup 2 */
#define VCAP_CID_INGRESS_STAGE2_L3 8300000 /* Ingress Stage 2 Lookup 3 */
#define VCAP_CID_EGRESS_L0 10000000 /* Egress Lookup 0 */
#define VCAP_CID_EGRESS_L1 10100000 /* Egress Lookup 1 */
#define VCAP_CID_EGRESS_STAGE2_L0 20000000 /* Egress Stage 2 Lookup 0 */
#define VCAP_CID_EGRESS_STAGE2_L1 20100000 /* Egress Stage 2 Lookup 1 */
/* Known users of the VCAP API */
enum vcap_user {
VCAP_USER_PTP,
VCAP_USER_MRP,
VCAP_USER_CFM,
VCAP_USER_VLAN,
VCAP_USER_QOS,
VCAP_USER_VCAP_UTIL,
VCAP_USER_TC,
VCAP_USER_TC_EXTRA,
/* add new users above here */
/* used to define VCAP_USER_MAX below */
__VCAP_USER_AFTER_LAST,
VCAP_USER_MAX = __VCAP_USER_AFTER_LAST - 1,
};
/* VCAP information used for displaying data */
struct vcap_statistics {
char *name;
int count;
const char * const *keyfield_set_names;
const char * const *actionfield_set_names;
const char * const *keyfield_names;
const char * const *actionfield_names;
};
/* VCAP key/action field type, position and width */
struct vcap_field {
u16 type;
u16 width;
u16 offset;
};
/* VCAP keyset or actionset type and width */
struct vcap_set {
u8 type_id;
u8 sw_per_item;
u8 sw_cnt;
};
/* VCAP typegroup position and bitvalue */
struct vcap_typegroup {
u16 offset;
u16 width;
u16 value;
};
/* VCAP model data */
struct vcap_info {
char *name; /* user-friendly name */
u16 rows; /* number of row in instance */
u16 sw_count; /* maximum subwords used per rule */
u16 sw_width; /* bits per subword in a keyset */
u16 sticky_width; /* sticky bits per rule */
u16 act_width; /* bits per subword in an actionset */
u16 default_cnt; /* number of default rules */
u16 require_cnt_dis; /* not used */
u16 version; /* vcap rtl version */
const struct vcap_set *keyfield_set; /* keysets */
int keyfield_set_size; /* number of keysets */
const struct vcap_set *actionfield_set; /* actionsets */
int actionfield_set_size; /* number of actionsets */
/* map of keys per keyset */
const struct vcap_field **keyfield_set_map;
/* number of entries in the above map */
int *keyfield_set_map_size;
/* map of actions per actionset */
const struct vcap_field **actionfield_set_map;
/* number of entries in the above map */
int *actionfield_set_map_size;
/* map of keyset typegroups per subword size */
const struct vcap_typegroup **keyfield_set_typegroups;
/* map of actionset typegroups per subword size */
const struct vcap_typegroup **actionfield_set_typegroups;
};
enum vcap_field_type {
VCAP_FIELD_BIT,
VCAP_FIELD_U32,
VCAP_FIELD_U48,
VCAP_FIELD_U56,
VCAP_FIELD_U64,
VCAP_FIELD_U72,
VCAP_FIELD_U112,
VCAP_FIELD_U128,
};
/* VCAP rule data towards the VCAP cache */
struct vcap_cache_data {
u32 *keystream;
u32 *maskstream;
u32 *actionstream;
u32 counter;
bool sticky;
};
/* Selects which part of the rule must be updated */
enum vcap_selection {
VCAP_SEL_ENTRY = 0x01,
VCAP_SEL_ACTION = 0x02,
VCAP_SEL_COUNTER = 0x04,
VCAP_SEL_ALL = 0xff,
};
/* Commands towards the VCAP cache */
enum vcap_command {
VCAP_CMD_WRITE = 0,
VCAP_CMD_READ = 1,
VCAP_CMD_MOVE_DOWN = 2,
VCAP_CMD_MOVE_UP = 3,
VCAP_CMD_INITIALIZE = 4,
};
enum vcap_rule_error {
VCAP_ERR_NONE = 0, /* No known error */
VCAP_ERR_NO_ADMIN, /* No admin instance */
VCAP_ERR_NO_NETDEV, /* No netdev instance */
VCAP_ERR_NO_KEYSET_MATCH, /* No keyset matched the rule keys */
VCAP_ERR_NO_ACTIONSET_MATCH, /* No actionset matched the rule actions */
VCAP_ERR_NO_PORT_KEYSET_MATCH, /* No port keyset matched the rule keys */
};
/* Administration of each VCAP instance */
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 */
struct vcap_control *vctrl; /* the control instance owning this vcap */
enum vcap_type vtype; /* type of vcap */
int vinst; /* instance number within the same type */
int first_cid; /* first chain id in this vcap */
int last_cid; /* last chain id in this vcap */
int tgt_inst; /* hardware instance number */
int lookups; /* number of lookups in this vcap type */
int lookups_per_instance; /* number of lookups in this instance */
int last_valid_addr; /* top of address range to be used */
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 */
};
/* Client supplied VCAP rule data */
struct vcap_rule {
int vcap_chain_id; /* chain used for this rule */
enum vcap_user user; /* rule owner */
u16 priority;
u32 id; /* vcap rule id, must be unique, 0 will auto-generate a value */
u64 cookie; /* used by the client to identify the rule */
struct list_head keyfields; /* list of vcap_client_keyfield */
struct list_head actionfields; /* list of vcap_client_actionfield */
enum vcap_keyfield_set keyset; /* keyset used: may be derived from fields */
enum vcap_actionfield_set actionset; /* actionset used: may be derived from fields */
enum vcap_rule_error exterr; /* extended error - used by TC */
u64 client; /* space for client defined data */
};
/* List of keysets */
struct vcap_keyset_list {
int max; /* size of the keyset list */
int cnt; /* count of keysets actually in the list */
enum vcap_keyfield_set *keysets; /* the list of keysets */
};
/* List of actionsets */
struct vcap_actionset_list {
int max; /* size of the actionset list */
int cnt; /* count of actionsets actually in the list */
enum vcap_actionfield_set *actionsets; /* the list of actionsets */
};
/* Client output printf-like function with destination */
struct vcap_output_print {
__printf(2, 3)
void (*prf)(void *out, const char *fmt, ...);
void *dst;
};
/* Client supplied VCAP callback operations */
struct vcap_operations {
/* validate port keyset operation */
enum vcap_keyfield_set (*validate_keyset)
(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule,
struct vcap_keyset_list *kslist,
u16 l3_proto);
/* add default rule fields for the selected keyset operations */
void (*add_default_fields)
(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule);
/* cache operations */
void (*cache_erase)
(struct vcap_admin *admin);
void (*cache_write)
(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel,
u32 idx, u32 count);
void (*cache_read)
(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel,
u32 idx,
u32 count);
/* block operations */
void (*init)
(struct net_device *ndev,
struct vcap_admin *admin,
u32 addr,
u32 count);
void (*update)
(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_command cmd,
enum vcap_selection sel,
u32 addr);
void (*move)
(struct net_device *ndev,
struct vcap_admin *admin,
u32 addr,
int offset,
int count);
/* informational */
int (*port_info)
(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out);
};
/* VCAP API Client control interface */
struct vcap_control {
const struct vcap_operations *ops; /* client supplied operations */
const struct vcap_info *vcaps; /* client supplied vcap models */
const struct vcap_statistics *stats; /* client supplied vcap stats */
struct list_head list; /* list of vcap instances */
struct mutex lock; /* serialize access to all vcap instances */
};
#endif /* __VCAP_API__ */
@@ -0,0 +1,284 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API_CLIENT__
#define __VCAP_API_CLIENT__
#include <linux/types.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <net/flow_offload.h>
#include "vcap_api.h"
/* Client supplied VCAP rule key control part */
struct vcap_client_keyfield_ctrl {
struct list_head list; /* For insertion into a rule */
enum vcap_key_field key;
enum vcap_field_type type;
};
struct vcap_u1_key {
u8 value;
u8 mask;
};
struct vcap_u32_key {
u32 value;
u32 mask;
};
struct vcap_u48_key {
u8 value[6];
u8 mask[6];
};
struct vcap_u56_key {
u8 value[7];
u8 mask[7];
};
struct vcap_u64_key {
u8 value[8];
u8 mask[8];
};
struct vcap_u72_key {
u8 value[9];
u8 mask[9];
};
struct vcap_u112_key {
u8 value[14];
u8 mask[14];
};
struct vcap_u128_key {
u8 value[16];
u8 mask[16];
};
/* Client supplied VCAP rule field data */
struct vcap_client_keyfield_data {
union {
struct vcap_u1_key u1;
struct vcap_u32_key u32;
struct vcap_u48_key u48;
struct vcap_u56_key u56;
struct vcap_u64_key u64;
struct vcap_u72_key u72;
struct vcap_u112_key u112;
struct vcap_u128_key u128;
};
};
/* Client supplied VCAP rule key (value, mask) */
struct vcap_client_keyfield {
struct vcap_client_keyfield_ctrl ctrl;
struct vcap_client_keyfield_data data;
};
/* Client supplied VCAP rule action control part */
struct vcap_client_actionfield_ctrl {
struct list_head list; /* For insertion into a rule */
enum vcap_action_field action;
enum vcap_field_type type;
};
struct vcap_u1_action {
u8 value;
};
struct vcap_u32_action {
u32 value;
};
struct vcap_u48_action {
u8 value[6];
};
struct vcap_u56_action {
u8 value[7];
};
struct vcap_u64_action {
u8 value[8];
};
struct vcap_u72_action {
u8 value[9];
};
struct vcap_u112_action {
u8 value[14];
};
struct vcap_u128_action {
u8 value[16];
};
struct vcap_client_actionfield_data {
union {
struct vcap_u1_action u1;
struct vcap_u32_action u32;
struct vcap_u48_action u48;
struct vcap_u56_action u56;
struct vcap_u64_action u64;
struct vcap_u72_action u72;
struct vcap_u112_action u112;
struct vcap_u128_action u128;
};
};
struct vcap_client_actionfield {
struct vcap_client_actionfield_ctrl ctrl;
struct vcap_client_actionfield_data data;
};
enum vcap_bit {
VCAP_BIT_ANY,
VCAP_BIT_0,
VCAP_BIT_1
};
struct vcap_counter {
u32 value;
bool sticky;
};
/* Enable/Disable the VCAP instance lookups */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int from_cid, int to_cid, 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,
struct net_device *ndev,
int vcap_chain_id,
enum vcap_user user,
u16 priority,
u32 id);
/* Free mem of a rule owned by client */
void vcap_free_rule(struct vcap_rule *rule);
/* Validate a rule before adding it to the VCAP */
int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto);
/* Add rule to a VCAP instance */
int vcap_add_rule(struct vcap_rule *rule);
/* Delete rule in a VCAP instance */
int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id);
/* Make a full copy of an existing rule with a new rule id */
struct vcap_rule *vcap_copy_rule(struct vcap_rule *rule);
/* Get rule from a VCAP instance */
struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id);
/* Update existing rule */
int vcap_mod_rule(struct vcap_rule *rule);
/* Update the keyset for the rule */
int vcap_set_rule_set_keyset(struct vcap_rule *rule,
enum vcap_keyfield_set keyset);
/* Update the actionset for the rule */
int vcap_set_rule_set_actionset(struct vcap_rule *rule,
enum vcap_actionfield_set actionset);
/* Set a rule counter id (for certain VCAPs only) */
void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id);
/* VCAP rule field operations */
int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
enum vcap_bit val);
int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
u32 value, u32 mask);
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);
int vcap_rule_add_action_u72(struct vcap_rule *rule, enum vcap_action_field action,
struct vcap_u72_action *fieldval);
/* Get number of rules in a vcap instance lookup chain id range */
int vcap_admin_rule_count(struct vcap_admin *admin, int cid);
/* VCAP rule counter operations */
int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl,
struct vcap_counter *ctr, u64 cookie);
int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr);
int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr);
/* 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 */
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);
/* Calculate the value used for chaining VCAP rules */
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 ingress);
/* Match a list of keys against the keysets available in a vcap type */
bool vcap_rule_find_keysets(struct vcap_rule *rule,
struct vcap_keyset_list *matches);
/* Return the keyset information for the keyset */
const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset);
/* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
/* Convert validation error code into tc extack error message */
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);
/* Drop keys in a keylist and any keys that are not supported by the keyset */
int vcap_filter_rule_keys(struct vcap_rule *rule,
enum vcap_key_field keylist[], int length,
bool drop_unsupported);
/* 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);
/* Modify a 32 bit key field with value and mask in the rule */
int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
u32 value, u32 mask);
/* Modify a 32 bit action field with value in the rule */
int vcap_rule_mod_action_u32(struct vcap_rule *rule,
enum vcap_action_field action,
u32 value);
/* Get a 32 bit key field value and mask from the rule */
int vcap_rule_get_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
u32 *value, u32 *mask);
/* Remove a key field with value and mask in the rule */
int vcap_rule_rem_key(struct vcap_rule *rule, enum vcap_key_field key);
/* Select the keyset from the list that results in the smallest rule size */
enum vcap_keyfield_set
vcap_select_min_rule_keyset(struct vcap_control *vctrl, enum vcap_type vtype,
struct vcap_keyset_list *kslist);
struct vcap_client_actionfield *
vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act);
#endif /* __VCAP_API_CLIENT__ */
@@ -0,0 +1,468 @@
// SPDX-License-Identifier: GPL-2.0+
/* Microchip VCAP API debug file system support
*
* Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*
*/
#include "vcap_api_private.h"
#include "vcap_api_debugfs.h"
struct vcap_admin_debugfs_info {
struct vcap_control *vctrl;
struct vcap_admin *admin;
};
struct vcap_port_debugfs_info {
struct vcap_control *vctrl;
struct net_device *ndev;
};
/* Dump the keyfields value and mask values */
static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
struct vcap_output_print *out,
enum vcap_key_field key,
const struct vcap_field *keyfield,
struct vcap_client_keyfield_data *data)
{
bool hex = false;
u8 *value, *mask;
int idx, bytes;
out->prf(out->dst, " %s: W%d: ", vcap_keyfield_name(vctrl, key),
keyfield[key].width);
switch (keyfield[key].type) {
case VCAP_FIELD_BIT:
out->prf(out->dst, "%d/%d", data->u1.value, data->u1.mask);
break;
case VCAP_FIELD_U32:
value = (u8 *)(&data->u32.value);
mask = (u8 *)(&data->u32.mask);
if (key == VCAP_KF_L3_IP4_SIP || key == VCAP_KF_L3_IP4_DIP) {
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_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);
}
break;
case VCAP_FIELD_U48:
value = data->u48.value;
mask = data->u48.mask;
if (key == VCAP_KF_L2_SMAC || key == VCAP_KF_L2_DMAC)
out->prf(out->dst, "%pMR/%pMR", data->u48.value,
data->u48.mask);
else
hex = true;
break;
case VCAP_FIELD_U56:
value = data->u56.value;
mask = data->u56.mask;
hex = true;
break;
case VCAP_FIELD_U64:
value = data->u64.value;
mask = data->u64.mask;
hex = true;
break;
case VCAP_FIELD_U72:
value = data->u72.value;
mask = data->u72.mask;
hex = true;
break;
case VCAP_FIELD_U112:
value = data->u112.value;
mask = data->u112.mask;
hex = true;
break;
case VCAP_FIELD_U128:
value = data->u128.value;
mask = data->u128.mask;
if (key == VCAP_KF_L3_IP6_SIP || key == VCAP_KF_L3_IP6_DIP) {
u8 nvalue[16], nmask[16];
vcap_netbytes_copy(nvalue, data->u128.value,
sizeof(nvalue));
vcap_netbytes_copy(nmask, data->u128.mask,
sizeof(nmask));
out->prf(out->dst, "%pI6/%pI6", nvalue, nmask);
} else {
hex = true;
}
break;
}
if (hex) {
bytes = DIV_ROUND_UP(keyfield[key].width, BITS_PER_BYTE);
out->prf(out->dst, "0x");
for (idx = 0; idx < bytes; ++idx)
out->prf(out->dst, "%02x", value[bytes - idx - 1]);
out->prf(out->dst, "/0x");
for (idx = 0; idx < bytes; ++idx)
out->prf(out->dst, "%02x", mask[bytes - idx - 1]);
}
out->prf(out->dst, "\n");
}
static void
vcap_debugfs_show_rule_actionfield(struct vcap_control *vctrl,
struct vcap_output_print *out,
enum vcap_action_field action,
const struct vcap_field *actionfield,
u8 *value)
{
bool hex = false;
int idx, bytes;
u32 fmsk, val;
out->prf(out->dst, " %s: W%d: ",
vcap_actionfield_name(vctrl, action),
actionfield[action].width);
switch (actionfield[action].type) {
case VCAP_FIELD_BIT:
out->prf(out->dst, "%d", value[0]);
break;
case VCAP_FIELD_U32:
fmsk = (1 << actionfield[action].width) - 1;
val = *(u32 *)value;
out->prf(out->dst, "%u", val & fmsk);
break;
case VCAP_FIELD_U48:
case VCAP_FIELD_U56:
case VCAP_FIELD_U64:
case VCAP_FIELD_U72:
case VCAP_FIELD_U112:
case VCAP_FIELD_U128:
hex = true;
break;
}
if (hex) {
bytes = DIV_ROUND_UP(actionfield[action].width, BITS_PER_BYTE);
out->prf(out->dst, "0x");
for (idx = 0; idx < bytes; ++idx)
out->prf(out->dst, "%02x", value[bytes - idx - 1]);
}
out->prf(out->dst, "\n");
}
static int vcap_debugfs_show_keysets(struct vcap_rule_internal *ri,
struct vcap_output_print *out)
{
struct vcap_admin *admin = ri->admin;
enum vcap_keyfield_set keysets[10];
struct vcap_keyset_list matches;
int err;
matches.keysets = keysets;
matches.cnt = 0;
matches.max = ARRAY_SIZE(keysets);
if (ri->state == VCAP_RS_DISABLED)
err = vcap_rule_get_keysets(ri, &matches);
else
err = vcap_find_keystream_keysets(ri->vctrl, admin->vtype,
admin->cache.keystream,
admin->cache.maskstream,
false, 0, &matches);
if (err) {
pr_err("%s:%d: could not find valid keysets: %d\n",
__func__, __LINE__, err);
return err;
}
out->prf(out->dst, " keysets:");
for (int idx = 0; idx < matches.cnt; ++idx)
out->prf(out->dst, " %s",
vcap_keyset_name(ri->vctrl, matches.keysets[idx]));
out->prf(out->dst, "\n");
return 0;
}
static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri,
struct vcap_output_print *out)
{
struct vcap_control *vctrl = ri->vctrl;
struct vcap_admin *admin = ri->admin;
const struct vcap_field *keyfield;
struct vcap_client_keyfield *ckf;
vcap_debugfs_show_keysets(ri, out);
out->prf(out->dst, " keyset_sw: %d\n", ri->keyset_sw);
out->prf(out->dst, " keyset_sw_regs: %d\n", ri->keyset_sw_regs);
list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
keyfield = vcap_keyfields(vctrl, admin->vtype, ri->data.keyset);
vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key,
keyfield, &ckf->data);
}
return 0;
}
static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri,
struct vcap_output_print *out)
{
struct vcap_control *vctrl = ri->vctrl;
struct vcap_admin *admin = ri->admin;
const struct vcap_field *actionfield;
struct vcap_client_actionfield *caf;
out->prf(out->dst, " actionset: %s\n",
vcap_actionset_name(vctrl, ri->data.actionset));
out->prf(out->dst, " actionset_sw: %d\n", ri->actionset_sw);
out->prf(out->dst, " actionset_sw_regs: %d\n", ri->actionset_sw_regs);
list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
actionfield = vcap_actionfields(vctrl, admin->vtype,
ri->data.actionset);
vcap_debugfs_show_rule_actionfield(vctrl, out, caf->ctrl.action,
actionfield,
&caf->data.u1.value);
}
return 0;
}
static void vcap_show_admin_rule(struct vcap_control *vctrl,
struct vcap_admin *admin,
struct vcap_output_print *out,
struct vcap_rule_internal *ri)
{
ri->counter.value = admin->cache.counter;
ri->counter.sticky = admin->cache.sticky;
out->prf(out->dst,
"rule: %u, addr: [%d,%d], X%d, ctr[%d]: %d, hit: %d\n",
ri->data.id, ri->addr, ri->addr + ri->size - 1, ri->size,
ri->counter_id, ri->counter.value, ri->counter.sticky);
out->prf(out->dst, " chain_id: %d\n", ri->data.vcap_chain_id);
out->prf(out->dst, " user: %d\n", ri->data.user);
out->prf(out->dst, " priority: %d\n", ri->data.priority);
out->prf(out->dst, " state: ");
switch (ri->state) {
case VCAP_RS_PERMANENT:
out->prf(out->dst, "permanent\n");
break;
case VCAP_RS_DISABLED:
out->prf(out->dst, "disabled\n");
break;
case VCAP_RS_ENABLED:
out->prf(out->dst, "enabled\n");
break;
}
vcap_debugfs_show_rule_keyset(ri, out);
vcap_debugfs_show_rule_actionset(ri, out);
}
static void vcap_show_admin_info(struct vcap_control *vctrl,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
const struct vcap_info *vcap = &vctrl->vcaps[admin->vtype];
out->prf(out->dst, "name: %s\n", vcap->name);
out->prf(out->dst, "rows: %d\n", vcap->rows);
out->prf(out->dst, "sw_count: %d\n", vcap->sw_count);
out->prf(out->dst, "sw_width: %d\n", vcap->sw_width);
out->prf(out->dst, "sticky_width: %d\n", vcap->sticky_width);
out->prf(out->dst, "act_width: %d\n", vcap->act_width);
out->prf(out->dst, "default_cnt: %d\n", vcap->default_cnt);
out->prf(out->dst, "require_cnt_dis: %d\n", vcap->require_cnt_dis);
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);
out->prf(out->dst, "first_valid_addr: %d\n", admin->first_valid_addr);
out->prf(out->dst, "last_valid_addr: %d\n", admin->last_valid_addr);
out->prf(out->dst, "last_used_addr: %d\n", admin->last_used_addr);
}
static int vcap_show_admin(struct vcap_control *vctrl,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
struct vcap_rule_internal *elem;
struct vcap_rule *vrule;
int ret = 0;
vcap_show_admin_info(vctrl, admin, out);
list_for_each_entry(elem, &admin->rules, list) {
vrule = vcap_decode_rule(elem);
if (IS_ERR(vrule)) {
ret = PTR_ERR(vrule);
break;
}
out->prf(out->dst, "\n");
vcap_show_admin_rule(vctrl, admin, out, to_intrule(vrule));
vcap_free_rule(vrule);
}
return ret;
}
static int vcap_show_admin_raw(struct vcap_control *vctrl,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
enum vcap_keyfield_set keysets[10];
enum vcap_type vt = admin->vtype;
struct vcap_keyset_list kslist;
struct vcap_rule_internal *ri;
const struct vcap_set *info;
int addr, idx;
int ret;
if (list_empty(&admin->rules))
return 0;
ret = vcap_api_check(vctrl);
if (ret)
return ret;
ri = list_first_entry(&admin->rules, struct vcap_rule_internal, list);
/* Go from higher to lower addresses searching for a keyset */
kslist.keysets = keysets;
kslist.max = ARRAY_SIZE(keysets);
for (addr = admin->last_valid_addr; addr >= admin->first_valid_addr;
--addr) {
kslist.cnt = 0;
ret = vcap_addr_keysets(vctrl, ri->ndev, admin, addr, &kslist);
if (ret < 0)
continue;
info = vcap_keyfieldset(vctrl, vt, kslist.keysets[0]);
if (!info)
continue;
if (addr % info->sw_per_item) {
pr_info("addr: %d X%d error rule, keyset: %s\n",
addr,
info->sw_per_item,
vcap_keyset_name(vctrl, kslist.keysets[0]));
} else {
out->prf(out->dst, " addr: %d, X%d rule, keysets:",
addr,
info->sw_per_item);
for (idx = 0; idx < kslist.cnt; ++idx)
out->prf(out->dst, " %s",
vcap_keyset_name(vctrl,
kslist.keysets[idx]));
out->prf(out->dst, "\n");
}
}
return 0;
}
/* Show the port configuration and status */
static int vcap_port_debugfs_show(struct seq_file *m, void *unused)
{
struct vcap_port_debugfs_info *info = m->private;
struct vcap_admin *admin;
struct vcap_output_print out = {
.prf = (void *)seq_printf,
.dst = m,
};
list_for_each_entry(admin, &info->vctrl->list, list) {
if (admin->vinst)
continue;
info->vctrl->ops->port_info(info->ndev, admin, &out);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(vcap_port_debugfs);
void vcap_port_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl,
struct net_device *ndev)
{
struct vcap_port_debugfs_info *info;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return;
info->vctrl = vctrl;
info->ndev = ndev;
debugfs_create_file(netdev_name(ndev), 0444, parent, info,
&vcap_port_debugfs_fops);
}
EXPORT_SYMBOL_GPL(vcap_port_debugfs);
/* Show the full VCAP instance data (rules with all fields) */
static int vcap_debugfs_show(struct seq_file *m, void *unused)
{
struct vcap_admin_debugfs_info *info = m->private;
struct vcap_output_print out = {
.prf = (void *)seq_printf,
.dst = m,
};
int ret;
vcap_lock(info->admin);
ret = vcap_show_admin(info->vctrl, info->admin, &out);
vcap_unlock(info->admin);
return ret;
}
DEFINE_SHOW_ATTRIBUTE(vcap_debugfs);
/* Show the raw VCAP instance data (rules with address info) */
static int vcap_raw_debugfs_show(struct seq_file *m, void *unused)
{
struct vcap_admin_debugfs_info *info = m->private;
struct vcap_output_print out = {
.prf = (void *)seq_printf,
.dst = m,
};
int ret;
vcap_lock(info->admin);
ret = vcap_show_admin_raw(info->vctrl, info->admin, &out);
vcap_unlock(info->admin);
return ret;
}
DEFINE_SHOW_ATTRIBUTE(vcap_raw_debugfs);
struct dentry *vcap_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl)
{
struct vcap_admin_debugfs_info *info;
struct vcap_admin *admin;
struct dentry *dir;
char name[50];
dir = debugfs_create_dir("vcaps", parent);
if (PTR_ERR_OR_ZERO(dir))
return NULL;
list_for_each_entry(admin, &vctrl->list, list) {
sprintf(name, "raw_%s_%d", vctrl->vcaps[admin->vtype].name,
admin->vinst);
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return NULL;
info->vctrl = vctrl;
info->admin = admin;
debugfs_create_file(name, 0444, dir, info,
&vcap_raw_debugfs_fops);
sprintf(name, "%s_%d", vctrl->vcaps[admin->vtype].name,
admin->vinst);
debugfs_create_file(name, 0444, dir, info, &vcap_debugfs_fops);
}
return dir;
}
EXPORT_SYMBOL_GPL(vcap_debugfs);
#ifdef CONFIG_VCAP_KUNIT_TEST
#include "vcap_api_debugfs_kunit.c"
#endif
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API_DEBUGFS__
#define __VCAP_API_DEBUGFS__
#include <linux/types.h>
#include <linux/debugfs.h>
#include <linux/netdevice.h>
#include "vcap_api.h"
#if defined(CONFIG_DEBUG_FS)
void vcap_port_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl,
struct net_device *ndev);
/* Create a debugFS entry for a vcap instance */
struct dentry *vcap_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl);
#else
static inline void vcap_port_debugfs(struct device *dev, struct dentry *parent,
struct vcap_control *vctrl,
struct net_device *ndev)
{
}
static inline struct dentry *vcap_debugfs(struct device *dev,
struct dentry *parent,
struct vcap_control *vctrl)
{
return NULL;
}
#endif
#endif /* __VCAP_API_DEBUGFS__ */
@@ -0,0 +1,555 @@
// SPDX-License-Identifier: BSD-3-Clause
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API kunit test suite
*/
#include <kunit/test.h>
#include "vcap_api.h"
#include "vcap_api_client.h"
#include "vcap_api_debugfs.h"
#include "vcap_model_kunit.h"
/* First we have the test infrastructure that emulates the platform
* implementation
*/
#define TEST_BUF_CNT 100
#define TEST_BUF_SZ 350
#define STREAMWSIZE 64
static u32 test_updateaddr[STREAMWSIZE] = {};
static int test_updateaddridx;
static int test_cache_erase_count;
static u32 test_init_start;
static u32 test_init_count;
static u32 test_hw_counter_id;
static struct vcap_cache_data test_hw_cache;
static struct net_device test_netdev = {};
static int test_move_addr;
static int test_move_offset;
static int test_move_count;
static char test_pr_buffer[TEST_BUF_CNT][TEST_BUF_SZ];
static int test_pr_bufferidx;
static int test_pr_idx;
/* Callback used by the VCAP API */
static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule,
struct vcap_keyset_list *kslist,
u16 l3_proto)
{
int idx;
if (kslist->cnt > 0) {
switch (admin->vtype) {
case VCAP_TYPE_IS0:
for (idx = 0; idx < kslist->cnt; idx++) {
if (kslist->keysets[idx] == VCAP_KFS_ETAG)
return kslist->keysets[idx];
if (kslist->keysets[idx] ==
VCAP_KFS_PURE_5TUPLE_IP4)
return kslist->keysets[idx];
if (kslist->keysets[idx] ==
VCAP_KFS_NORMAL_5TUPLE_IP4)
return kslist->keysets[idx];
if (kslist->keysets[idx] ==
VCAP_KFS_NORMAL_7TUPLE)
return kslist->keysets[idx];
}
break;
case VCAP_TYPE_IS2:
for (idx = 0; idx < kslist->cnt; idx++) {
if (kslist->keysets[idx] == VCAP_KFS_MAC_ETYPE)
return kslist->keysets[idx];
if (kslist->keysets[idx] == VCAP_KFS_ARP)
return kslist->keysets[idx];
if (kslist->keysets[idx] == VCAP_KFS_IP_7TUPLE)
return kslist->keysets[idx];
}
break;
default:
pr_info("%s:%d: no validation for VCAP %d\n",
__func__, __LINE__, admin->vtype);
break;
}
}
return -EINVAL;
}
/* Callback used by the VCAP API */
static void test_add_def_fields(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_rule *rule)
{
if (admin->vinst == 0 || admin->vinst == 2)
vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
VCAP_BIT_1);
else
vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
VCAP_BIT_0);
}
/* Callback used by the VCAP API */
static void test_cache_erase(struct vcap_admin *admin)
{
if (test_cache_erase_count) {
memset(admin->cache.keystream, 0, test_cache_erase_count);
memset(admin->cache.maskstream, 0, test_cache_erase_count);
memset(admin->cache.actionstream, 0, test_cache_erase_count);
test_cache_erase_count = 0;
}
}
/* Callback used by the VCAP API */
static void test_cache_init(struct net_device *ndev, struct vcap_admin *admin,
u32 start, u32 count)
{
test_init_start = start;
test_init_count = count;
}
/* Callback used by the VCAP API */
static void test_cache_read(struct net_device *ndev, struct vcap_admin *admin,
enum vcap_selection sel, u32 start, u32 count)
{
u32 *keystr, *mskstr, *actstr;
int idx;
pr_debug("%s:%d: %d %d\n", __func__, __LINE__, start, count);
switch (sel) {
case VCAP_SEL_ENTRY:
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
for (idx = 0; idx < count; ++idx) {
pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, keystr[idx]);
}
for (idx = 0; idx < count; ++idx) {
/* Invert the mask before decoding starts */
mskstr[idx] = ~mskstr[idx];
pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, mskstr[idx]);
}
break;
case VCAP_SEL_ACTION:
actstr = &admin->cache.actionstream[start];
for (idx = 0; idx < count; ++idx) {
pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, actstr[idx]);
}
break;
case VCAP_SEL_COUNTER:
pr_debug("%s:%d\n", __func__, __LINE__);
test_hw_counter_id = start;
admin->cache.counter = test_hw_cache.counter;
admin->cache.sticky = test_hw_cache.sticky;
break;
case VCAP_SEL_ALL:
pr_debug("%s:%d\n", __func__, __LINE__);
break;
}
}
/* Callback used by the VCAP API */
static void test_cache_write(struct net_device *ndev, struct vcap_admin *admin,
enum vcap_selection sel, u32 start, u32 count)
{
u32 *keystr, *mskstr, *actstr;
int idx;
switch (sel) {
case VCAP_SEL_ENTRY:
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
for (idx = 0; idx < count; ++idx) {
pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, keystr[idx]);
}
for (idx = 0; idx < count; ++idx) {
/* Invert the mask before encoding starts */
mskstr[idx] = ~mskstr[idx];
pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, mskstr[idx]);
}
break;
case VCAP_SEL_ACTION:
actstr = &admin->cache.actionstream[start];
for (idx = 0; idx < count; ++idx) {
pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__,
__LINE__, start + idx, actstr[idx]);
}
break;
case VCAP_SEL_COUNTER:
pr_debug("%s:%d\n", __func__, __LINE__);
test_hw_counter_id = start;
test_hw_cache.counter = admin->cache.counter;
test_hw_cache.sticky = admin->cache.sticky;
break;
case VCAP_SEL_ALL:
pr_err("%s:%d: cannot write all streams at once\n",
__func__, __LINE__);
break;
}
}
/* Callback used by the VCAP API */
static void test_cache_update(struct net_device *ndev, struct vcap_admin *admin,
enum vcap_command cmd,
enum vcap_selection sel, u32 addr)
{
if (test_updateaddridx < ARRAY_SIZE(test_updateaddr))
test_updateaddr[test_updateaddridx] = addr;
else
pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
test_updateaddridx);
test_updateaddridx++;
}
static void test_cache_move(struct net_device *ndev, struct vcap_admin *admin,
u32 addr, int offset, int count)
{
test_move_addr = addr;
test_move_offset = offset;
test_move_count = count;
}
/* Provide port information via a callback interface */
static int vcap_test_port_info(struct net_device *ndev,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
return 0;
}
static const struct vcap_operations test_callbacks = {
.validate_keyset = test_val_keyset,
.add_default_fields = test_add_def_fields,
.cache_erase = test_cache_erase,
.cache_write = test_cache_write,
.cache_read = test_cache_read,
.init = test_cache_init,
.update = test_cache_update,
.move = test_cache_move,
.port_info = vcap_test_port_info,
};
static struct vcap_control test_vctrl = {
.vcaps = kunit_test_vcaps,
.stats = &kunit_test_vcap_stats,
.ops = &test_callbacks,
};
static void vcap_test_api_init(struct vcap_admin *admin)
{
/* Initialize the shared objects */
INIT_LIST_HEAD(&test_vctrl.list);
mutex_init(&test_vctrl.lock);
INIT_LIST_HEAD(&admin->list);
INIT_LIST_HEAD(&admin->rules);
INIT_LIST_HEAD(&admin->enabled);
admin->vctrl = &test_vctrl;
list_add_tail(&admin->list, &test_vctrl.list);
memset(test_updateaddr, 0, sizeof(test_updateaddr));
test_updateaddridx = 0;
test_pr_bufferidx = 0;
test_pr_idx = 0;
}
/* callback used by the show_admin function */
static __printf(2, 3)
int test_prf(void *out, const char *fmt, ...)
{
static char test_buffer[TEST_BUF_SZ];
va_list args;
int idx, cnt;
if (test_pr_bufferidx >= TEST_BUF_CNT) {
pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
test_pr_bufferidx);
return 0;
}
va_start(args, fmt);
cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args);
va_end(args);
for (idx = 0; idx < cnt; ++idx) {
test_pr_buffer[test_pr_bufferidx][test_pr_idx] =
test_buffer[idx];
if (test_buffer[idx] == '\n') {
test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0;
test_pr_idx = 0;
test_pr_bufferidx++;
} else {
++test_pr_idx;
}
}
return cnt;
}
/* Define the test cases. */
static void vcap_api_addr_keyset_test(struct kunit *test)
{
u32 keydata[12] = {
0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
0x10203040, 0x00075880, 0x633c6864, 0x00040003,
0x00000020, 0x00000008, 0x00000240, 0x00000000,
};
u32 mskdata[12] = {
0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
};
u32 actdata[12] = {};
struct vcap_admin admin = {
.vtype = VCAP_TYPE_IS2,
.cache = {
.keystream = keydata,
.maskstream = mskdata,
.actionstream = actdata,
},
};
enum vcap_keyfield_set keysets[10];
struct vcap_keyset_list matches;
int ret, idx, addr;
vcap_test_api_init(&admin);
/* Go from higher to lower addresses searching for a keyset */
matches.keysets = keysets;
matches.cnt = 0;
matches.max = ARRAY_SIZE(keysets);
for (idx = ARRAY_SIZE(keydata) - 1, addr = 799; idx > 0;
--idx, --addr) {
admin.cache.keystream = &keydata[idx];
admin.cache.maskstream = &mskdata[idx];
ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
addr, &matches);
KUNIT_EXPECT_EQ(test, -EINVAL, ret);
}
/* Finally we hit the start of the rule */
admin.cache.keystream = &keydata[idx];
admin.cache.maskstream = &mskdata[idx];
matches.cnt = 0;
ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
addr, &matches);
KUNIT_EXPECT_EQ(test, 0, ret);
KUNIT_EXPECT_EQ(test, matches.cnt, 1);
KUNIT_EXPECT_EQ(test, matches.keysets[0], VCAP_KFS_MAC_ETYPE);
}
static void vcap_api_show_admin_raw_test(struct kunit *test)
{
u32 keydata[4] = {
0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
};
u32 mskdata[4] = {
0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
};
u32 actdata[12] = {};
struct vcap_admin admin = {
.vtype = VCAP_TYPE_IS2,
.cache = {
.keystream = keydata,
.maskstream = mskdata,
.actionstream = actdata,
},
.first_valid_addr = 786,
.last_valid_addr = 788,
};
struct vcap_rule_internal ri = {
.ndev = &test_netdev,
};
struct vcap_output_print out = {
.prf = (void *)test_prf,
};
const char *test_expected =
" addr: 786, X6 rule, keysets: VCAP_KFS_MAC_ETYPE\n";
int ret;
vcap_test_api_init(&admin);
list_add_tail(&ri.list, &admin.rules);
ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
KUNIT_EXPECT_EQ(test, 0, ret);
KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
}
static const char * const test_admin_info_expect[] = {
"name: is2\n",
"rows: 256\n",
"sw_count: 12\n",
"sw_width: 52\n",
"sticky_width: 1\n",
"act_width: 110\n",
"default_cnt: 73\n",
"require_cnt_dis: 0\n",
"version: 1\n",
"vtype: 4\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 10000\n",
"last_cid: 19999\n",
"lookups: 4\n",
"first_valid_addr: 0\n",
"last_valid_addr: 3071\n",
"last_used_addr: 794\n",
};
static void vcap_api_show_admin_test(struct kunit *test)
{
struct vcap_admin admin = {
.vtype = VCAP_TYPE_IS2,
.first_cid = 10000,
.last_cid = 19999,
.lookups = 4,
.last_valid_addr = 3071,
.first_valid_addr = 0,
.last_used_addr = 794,
.ingress = true,
};
struct vcap_output_print out = {
.prf = (void *)test_prf,
};
int idx;
vcap_test_api_init(&admin);
vcap_show_admin_info(&test_vctrl, &admin, &out);
for (idx = 0; idx < test_pr_bufferidx; ++idx) {
/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
test_pr_buffer[idx]);
}
}
static const char * const test_admin_expect[] = {
"name: is2\n",
"rows: 256\n",
"sw_count: 12\n",
"sw_width: 52\n",
"sticky_width: 1\n",
"act_width: 110\n",
"default_cnt: 73\n",
"require_cnt_dis: 0\n",
"version: 1\n",
"vtype: 4\n",
"vinst: 0\n",
"ingress: 1\n",
"first_cid: 8000000\n",
"last_cid: 8199999\n",
"lookups: 4\n",
"first_valid_addr: 0\n",
"last_valid_addr: 3071\n",
"last_used_addr: 794\n",
"\n",
"rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
" chain_id: 0\n",
" user: 0\n",
" priority: 0\n",
" state: permanent\n",
" keysets: VCAP_KFS_MAC_ETYPE\n",
" keyset_sw: 6\n",
" keyset_sw_regs: 2\n",
" ETYPE_LEN_IS: W1: 1/1\n",
" IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
" IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
" L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
" L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
" L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
" LOOKUP_FIRST_IS: W1: 1/1\n",
" TYPE: W4: 0/15\n",
" actionset: VCAP_AFS_BASE_TYPE\n",
" actionset_sw: 3\n",
" actionset_sw_regs: 4\n",
" CNT_ID: W12: 100\n",
" MATCH_ID: W16: 1\n",
" MATCH_ID_MASK: W16: 1\n",
" POLICE_ENA: W1: 1\n",
" PORT_MASK: W68: 0x0514670115f3324589\n",
};
static void vcap_api_show_admin_rule_test(struct kunit *test)
{
u32 keydata[] = {
0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
0x10203040, 0x00075880, 0x633c6864, 0x00040003,
0x00000020, 0x00000008, 0x00000240, 0x00000000,
};
u32 mskdata[] = {
0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
};
u32 actdata[] = {
0x00040002, 0xf3324589, 0x14670115, 0x00000005,
0x00000000, 0x00100000, 0x06400010, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
struct vcap_admin admin = {
.vtype = VCAP_TYPE_IS2,
.first_cid = 8000000,
.last_cid = 8199999,
.lookups = 4,
.last_valid_addr = 3071,
.first_valid_addr = 0,
.last_used_addr = 794,
.ingress = true,
.cache = {
.keystream = keydata,
.maskstream = mskdata,
.actionstream = actdata,
},
};
struct vcap_rule_internal ri = {
.admin = &admin,
.data = {
.id = 100,
.keyset = VCAP_KFS_MAC_ETYPE,
.actionset = VCAP_AFS_BASE_TYPE,
},
.size = 6,
.keyset_sw = 6,
.keyset_sw_regs = 2,
.actionset_sw = 3,
.actionset_sw_regs = 4,
.addr = 794,
.vctrl = &test_vctrl,
};
struct vcap_output_print out = {
.prf = (void *)test_prf,
};
int ret, idx;
vcap_test_api_init(&admin);
list_add_tail(&ri.list, &admin.rules);
ret = vcap_show_admin(&test_vctrl, &admin, &out);
KUNIT_EXPECT_EQ(test, 0, ret);
for (idx = 0; idx < test_pr_bufferidx; ++idx) {
/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
KUNIT_EXPECT_STREQ(test, test_admin_expect[idx],
test_pr_buffer[idx]);
}
}
static struct kunit_case vcap_api_debugfs_test_cases[] = {
KUNIT_CASE(vcap_api_addr_keyset_test),
KUNIT_CASE(vcap_api_show_admin_raw_test),
KUNIT_CASE(vcap_api_show_admin_test),
KUNIT_CASE(vcap_api_show_admin_rule_test),
{}
};
static struct kunit_suite vcap_api_debugfs_test_suite = {
.name = "VCAP_API_DebugFS_Testsuite",
.test_cases = vcap_api_debugfs_test_cases,
};
kunit_test_suite(vcap_api_debugfs_test_suite);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,127 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP API
*/
#ifndef __VCAP_API_PRIVATE__
#define __VCAP_API_PRIVATE__
#include <linux/types.h>
#include "vcap_api.h"
#include "vcap_api_client.h"
#define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data)
enum vcap_rule_state {
VCAP_RS_PERMANENT, /* the rule is always stored in HW */
VCAP_RS_ENABLED, /* enabled in HW but can be disabled */
VCAP_RS_DISABLED, /* disabled (stored in SW) and can be enabled */
};
/* Private VCAP API rule data */
struct vcap_rule_internal {
struct vcap_rule data; /* provided by the client */
struct list_head list; /* the vcap admin list of rules */
struct vcap_admin *admin; /* vcap hw instance */
struct net_device *ndev; /* the interface that the rule applies to */
struct vcap_control *vctrl; /* the client control */
u32 sort_key; /* defines the position in the VCAP */
int keyset_sw; /* subwords in a keyset */
int actionset_sw; /* subwords in an actionset */
int keyset_sw_regs; /* registers in a subword in an keyset */
int actionset_sw_regs; /* registers in a subword in an actionset */
int size; /* the size of the rule: max(entry, action) */
u32 addr; /* address in the VCAP at insertion */
u32 counter_id; /* counter id (if a dedicated counter is available) */
struct vcap_counter counter; /* last read counter value */
enum vcap_rule_state state; /* rule storage state */
};
/* Bit iterator for the VCAP cache streams */
struct vcap_stream_iter {
u32 offset; /* bit offset from the stream start */
u32 sw_width; /* subword width in bits */
u32 regs_per_sw; /* registers per subword */
u32 reg_idx; /* current register index */
u32 reg_bitpos; /* bit offset in current register */
const struct vcap_typegroup *tg; /* current typegroup */
};
/* Check that the control has a valid set of callbacks */
int vcap_api_check(struct vcap_control *ctrl);
/* Serialize access to the vcap instances of a control */
void vcap_lock(struct vcap_admin *admin);
void vcap_unlock(struct vcap_admin *admin);
/* Erase the VCAP cache area used or encoding and decoding */
void vcap_erase_cache(struct vcap_rule_internal *ri);
/* Iterator functionality */
void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset);
void vcap_iter_next(struct vcap_stream_iter *itr);
void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width,
const struct vcap_typegroup *tg, u32 offset);
void vcap_iter_update(struct vcap_stream_iter *itr);
/* Keyset and keyfield functionality */
/* Return the number of keyfields in the keyset */
int vcap_keyfield_count(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset);
/* Return the typegroup table for the matching keyset (using subword size) */
const struct vcap_typegroup *
vcap_keyfield_typegroup(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_keyfield_set keyset);
/* Return the list of keyfields for the keyset */
const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_keyfield_set keyset);
/* Actionset and actionfield functionality */
/* Return the actionset information for the actionset */
const struct vcap_set *
vcap_actionfieldset(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset);
/* Return the number of actionfields in the actionset */
int vcap_actionfield_count(struct vcap_control *vctrl,
enum vcap_type vt,
enum vcap_actionfield_set actionset);
/* Return the typegroup table for the matching actionset (using subword size) */
const struct vcap_typegroup *
vcap_actionfield_typegroup(struct vcap_control *vctrl, enum vcap_type vt,
enum vcap_actionfield_set actionset);
/* Return the list of actionfields for the actionset */
const struct vcap_field *
vcap_actionfields(struct vcap_control *vctrl,
enum vcap_type vt, enum vcap_actionfield_set actionset);
/* Map actionset id to a string with the actionset name */
const char *vcap_actionset_name(struct vcap_control *vctrl,
enum vcap_actionfield_set actionset);
/* Map key field id to a string with the key name */
const char *vcap_actionfield_name(struct vcap_control *vctrl,
enum vcap_action_field action);
/* Read key data from a VCAP address and discover if there are any rule keysets
* here
*/
int vcap_addr_keysets(struct vcap_control *vctrl, struct net_device *ndev,
struct vcap_admin *admin, int addr,
struct vcap_keyset_list *kslist);
/* Verify that the typegroup information, subword count, keyset and type id
* are in sync and correct, return the list of matching keysets
*/
int vcap_find_keystream_keysets(struct vcap_control *vctrl, enum vcap_type vt,
u32 *keystream, u32 *mskstream, bool mask,
int sw_max, struct vcap_keyset_list *kslist);
/* 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);
/* Decode a rule from the VCAP cache and return a copy */
struct vcap_rule *vcap_decode_rule(struct vcap_rule_internal *elem);
#endif /* __VCAP_API_PRIVATE__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP test model interface for kunit testing
*/
/* This file is autogenerated by cml-utils 2023-02-10 11:16:00 +0100.
* Commit ID: c30fb4bf0281cd4a7133bdab6682f9e43c872ada
*/
#ifndef __VCAP_MODEL_KUNIT_H__
#define __VCAP_MODEL_KUNIT_H__
/* VCAPs */
extern const struct vcap_info kunit_test_vcaps[];
extern const struct vcap_statistics kunit_test_vcap_stats;
#endif /* __VCAP_MODEL_KUNIT_H__ */
@@ -0,0 +1,412 @@
// SPDX-License-Identifier: GPL-2.0+
/* Microchip VCAP TC
*
* Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
*/
#include <net/flow_offload.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include "vcap_api_client.h"
#include "vcap_tc.h"
enum vcap_is2_arp_opcode {
VCAP_IS2_ARP_REQUEST,
VCAP_IS2_ARP_REPLY,
VCAP_IS2_RARP_REQUEST,
VCAP_IS2_RARP_REPLY,
};
enum vcap_arp_opcode {
VCAP_ARP_OP_RESERVED,
VCAP_ARP_OP_REQUEST,
VCAP_ARP_OP_REPLY,
};
int vcap_tc_flower_handler_ethaddr_usage(struct vcap_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_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ethaddr_usage);
int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st)
{
int err = 0;
if (st->l3_proto == ETH_P_IP) {
struct flow_match_ipv4_addrs mt;
flow_rule_match_ipv4_addrs(st->frule, &mt);
if (mt.mask->src) {
err = vcap_rule_add_key_u32(st->vrule,
VCAP_KF_L3_IP4_SIP,
be32_to_cpu(mt.key->src),
be32_to_cpu(mt.mask->src));
if (err)
goto out;
}
if (mt.mask->dst) {
err = vcap_rule_add_key_u32(st->vrule,
VCAP_KF_L3_IP4_DIP,
be32_to_cpu(mt.key->dst),
be32_to_cpu(mt.mask->dst));
if (err)
goto out;
}
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv4_usage);
int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st)
{
int err = 0;
if (st->l3_proto == ETH_P_IPV6) {
struct flow_match_ipv6_addrs mt;
struct vcap_u128_key sip;
struct vcap_u128_key dip;
flow_rule_match_ipv6_addrs(st->frule, &mt);
/* Check if address masks are non-zero */
if (!ipv6_addr_any(&mt.mask->src)) {
vcap_netbytes_copy(sip.value, mt.key->src.s6_addr, 16);
vcap_netbytes_copy(sip.mask, mt.mask->src.s6_addr, 16);
err = vcap_rule_add_key_u128(st->vrule,
VCAP_KF_L3_IP6_SIP, &sip);
if (err)
goto out;
}
if (!ipv6_addr_any(&mt.mask->dst)) {
vcap_netbytes_copy(dip.value, mt.key->dst.s6_addr, 16);
vcap_netbytes_copy(dip.mask, mt.mask->dst.s6_addr, 16);
err = vcap_rule_add_key_u128(st->vrule,
VCAP_KF_L3_IP6_DIP, &dip);
if (err)
goto out;
}
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv6_usage);
int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st)
{
struct flow_match_ports mt;
u16 value, mask;
int err = 0;
flow_rule_match_ports(st->frule, &mt);
if (mt.mask->src) {
value = be16_to_cpu(mt.key->src);
mask = be16_to_cpu(mt.mask->src);
err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_SPORT, value,
mask);
if (err)
goto out;
}
if (mt.mask->dst) {
value = be16_to_cpu(mt.key->dst);
mask = be16_to_cpu(mt.mask->dst);
err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L4_DPORT, value,
mask);
if (err)
goto out;
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_PORTS);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_portnum_usage);
int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
{
enum vcap_key_field vid_key = VCAP_KF_8021Q_VID0;
enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP0;
struct flow_match_vlan mt;
u16 tpid;
int err;
flow_rule_match_cvlan(st->frule, &mt);
tpid = be16_to_cpu(mt.key->vlan_tpid);
if (tpid == ETH_P_8021Q) {
vid_key = VCAP_KF_8021Q_VID1;
pcp_key = VCAP_KF_8021Q_PCP1;
}
if (mt.mask->vlan_id) {
err = vcap_rule_add_key_u32(st->vrule, vid_key,
mt.key->vlan_id,
mt.mask->vlan_id);
if (err)
goto out;
}
if (mt.mask->vlan_priority) {
err = vcap_rule_add_key_u32(st->vrule, pcp_key,
mt.key->vlan_priority,
mt.mask->vlan_priority);
if (err)
goto out;
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN);
return 0;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_cvlan_usage);
int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
enum vcap_key_field vid_key,
enum vcap_key_field pcp_key)
{
struct flow_match_vlan mt;
int err;
flow_rule_match_vlan(st->frule, &mt);
if (mt.mask->vlan_id) {
err = vcap_rule_add_key_u32(st->vrule, vid_key,
mt.key->vlan_id,
mt.mask->vlan_id);
if (err)
goto out;
}
if (mt.mask->vlan_priority) {
err = vcap_rule_add_key_u32(st->vrule, pcp_key,
mt.key->vlan_priority,
mt.mask->vlan_priority);
if (err)
goto out;
}
if (mt.mask->vlan_tpid)
st->tpid = be16_to_cpu(mt.key->vlan_tpid);
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_VLAN);
return 0;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_vlan_usage);
int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st)
{
struct flow_match_tcp mt;
u16 tcp_flags_mask;
u16 tcp_flags_key;
enum vcap_bit val;
int err = 0;
flow_rule_match_tcp(st->frule, &mt);
tcp_flags_key = be16_to_cpu(mt.key->flags);
tcp_flags_mask = be16_to_cpu(mt.mask->flags);
if (tcp_flags_mask & TCPHDR_FIN) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_FIN)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_FIN, val);
if (err)
goto out;
}
if (tcp_flags_mask & TCPHDR_SYN) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_SYN)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_SYN, val);
if (err)
goto out;
}
if (tcp_flags_mask & TCPHDR_RST) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_RST)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_RST, val);
if (err)
goto out;
}
if (tcp_flags_mask & TCPHDR_PSH) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_PSH)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_PSH, val);
if (err)
goto out;
}
if (tcp_flags_mask & TCPHDR_ACK) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_ACK)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_ACK, val);
if (err)
goto out;
}
if (tcp_flags_mask & TCPHDR_URG) {
val = VCAP_BIT_0;
if (tcp_flags_key & TCPHDR_URG)
val = VCAP_BIT_1;
err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_L4_URG, val);
if (err)
goto out;
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_TCP);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_tcp_usage);
int vcap_tc_flower_handler_arp_usage(struct vcap_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 == VCAP_ARP_OP_REQUEST ?
VCAP_IS2_ARP_REQUEST :
VCAP_IS2_ARP_REPLY;
} else { /* RARP */
value = mt.key->op == VCAP_ARP_OP_REQUEST ?
VCAP_IS2_RARP_REQUEST :
VCAP_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)) {
err = -EINVAL;
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_ULL(FLOW_DISSECTOR_KEY_ARP);
return 0;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_arp_usage);
int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st)
{
struct flow_match_ip mt;
int err = 0;
flow_rule_match_ip(st->frule, &mt);
if (mt.mask->tos) {
err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_L3_TOS,
mt.key->tos,
mt.mask->tos);
if (err)
goto out;
}
st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP);
return err;
out:
NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error");
return err;
}
EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ip_usage);
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries.
* Microchip VCAP TC
*/
#ifndef __VCAP_TC__
#define __VCAP_TC__
struct vcap_tc_flower_parse_usage {
struct flow_cls_offload *fco;
struct flow_rule *frule;
struct vcap_rule *vrule;
struct vcap_admin *admin;
u16 l3_proto;
u8 l4_proto;
u16 tpid;
unsigned long long used_keys;
};
int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
enum vcap_key_field vid_key,
enum vcap_key_field pcp_key);
int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st);
int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st);
#endif /* __VCAP_TC__ */