From patchwork Thu Oct 27 14:42:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steen Hegelund X-Patchwork-Id: 13022222 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5B54FA3741 for ; Thu, 27 Oct 2022 14:43:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235574AbiJ0OnX (ORCPT ); Thu, 27 Oct 2022 10:43:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235512AbiJ0OnW (ORCPT ); Thu, 27 Oct 2022 10:43:22 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D70618A51C; Thu, 27 Oct 2022 07:43:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1666881801; x=1698417801; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZDHBa9bzc08ycTyWSkWtXZaUle+cl64Y3IvIAL+eqRc=; b=JIidQcHBGw5tusk87NTbU1HJ7/hvbpCbJywxqCUFGdj92q1MoByYzMYa Kqv3xMKZPM3iDB7wGvGC1i9oI4276BowmQeHsBNWBhX1cgNxpnuHLVVvr bb7jEDwOJ1/zQ/RnFtkieb2bww6+z+mj2ZtDE/w5o2su/lEPytW0wvjHu 2fR/JHKNP1WJPec0Fhei7v3XRPCsFfc9z7irDGvsYHEsIWWQ6zSwFUXd9 Zt8LViV2UFtC485rbWeqcPpHhx+UJ1G2bhGpC70bGF8Q0Oat38Pt5q2r/ /vnpMp8W7N6piyMKDAg2pYnLGIU+Mjykh0WGmd91QDAzTGg5NVPtT2iWv A==; X-IronPort-AV: E=Sophos;i="5.95,217,1661842800"; d="scan'208";a="197302407" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Oct 2022 07:43:20 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Thu, 27 Oct 2022 07:43:20 -0700 Received: from den-dk-m31857.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Thu, 27 Oct 2022 07:43:17 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Daniel Machon" , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 1/5] net: microchip: sparx5: Differentiate IPv4 and IPv6 traffic in keyset config Date: Thu, 27 Oct 2022 16:42:56 +0200 Message-ID: <20221027144300.2936955-2-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027144300.2936955-1-steen.hegelund@microchip.com> References: <20221027144300.2936955-1-steen.hegelund@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This changes the port keyset configuration for Sparx5 IS2 so that - IPv4 generates a IP4_TCP_UDP keyset for IPv4 TCP/UDP frames and a IP4_OTHER keyset for other IPv4 frames (both UC and MC) - IPv6 generates a IP_7TUPLE keyset (both UC and MC) ARP and non-IP traffic continues to generate the MAC_ETYPE keyset Signed-off-by: Steen Hegelund --- .../microchip/sparx5/sparx5_vcap_impl.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index 50153264179e..e4428d55af2b 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -21,6 +21,14 @@ #define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ #define SPARX5_IS2_LOOKUPS 4 +#define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \ + (ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \ + ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \ + ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(_v4_mc) | \ + ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(_v4_uc) | \ + ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(_v6_mc) | \ + ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \ + ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp)) /* IS2 port keyset selection control */ @@ -368,13 +376,12 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, /* all traffic types generate the MAC_ETYPE keyset for now in all * lookups on all ports */ - keysel = ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(true) | - ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(VCAP_IS2_PS_NONETH_MAC_ETYPE) | - ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_MC_MAC_ETYPE) | - ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV4_UC_MAC_ETYPE) | - ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_MC_MAC_ETYPE) | - ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(VCAP_IS2_PS_IPV6_UC_MAC_ETYPE) | - ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(VCAP_IS2_PS_ARP_MAC_ETYPE); + keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE, + VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, + VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, + VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, + VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, + VCAP_IS2_PS_ARP_MAC_ETYPE); for (lookup = 0; lookup < admin->lookups; ++lookup) { for (portno = 0; portno < SPX5_PORTS; ++portno) { spx5_wr(keysel, sparx5, From patchwork Thu Oct 27 14:42:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steen Hegelund X-Patchwork-Id: 13022223 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83568ECAAA1 for ; Thu, 27 Oct 2022 14:43:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235729AbiJ0Onb (ORCPT ); Thu, 27 Oct 2022 10:43:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235580AbiJ0On0 (ORCPT ); Thu, 27 Oct 2022 10:43:26 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B338918A509; Thu, 27 Oct 2022 07:43:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1666881805; x=1698417805; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=EogV7kDffebmknKxkiQqvD0/UpxCaCmuGmNOortyWOc=; b=Ss2HdKNyvWmKSBmQVqgtvsSYh4qyoSgApbg5u0MGLmQtj8dVfOe1h+x8 8YxCNIEqCC5L4EiwLoeMfJZSeZTqIHGmnajT3jwwVNkDsYuK7q0lD0LHW xWOKduzrqgO9kRTp3/icS1Qp+XvKiifVvrVhECGkb4ZsgRQfukLBaOkA9 g5E9TAQhH3Ga8ZxJkOY8PJnmOuZlCyBhYE8r53vEJqqt3stbmIhhCm8EK p6IWWbHzhYHvwzJTZm3WeenFrzilFbCuL/Tpr4U8whaNdSeFaKXYE633Y JTctY9kXUThPf1sYzK7rGfk0in7gKpEvpkxAXMyGg0AfRaE4pU3RXcTUV g==; X-IronPort-AV: E=Sophos;i="5.95,217,1661842800"; d="scan'208";a="186548704" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Oct 2022 07:43:25 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Thu, 27 Oct 2022 07:43:23 -0700 Received: from den-dk-m31857.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Thu, 27 Oct 2022 07:43:20 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Daniel Machon" , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 2/5] net: microchip: sparx5: Adding more tc flower keys for the IS2 VCAP Date: Thu, 27 Oct 2022 16:42:57 +0200 Message-ID: <20221027144300.2936955-3-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027144300.2936955-1-steen.hegelund@microchip.com> References: <20221027144300.2936955-1-steen.hegelund@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This adds the following TC flower filter keys to Sparx5 for IS2: - ipv4_addr (sip and dip) - ipv6_addr (sip and dip) - control (IPv4 fragments) - portnum (tcp and udp port numbers) - basic (L3 and L4 protocol) - vlan (outer vlan tag info) - tcp (tcp flags) - ip (tos field) as well as an 128 bit keyfield interface on the VCAP API to set the IPv6 addresses. IS2 supports the classified VLAN information which amounts to the outer VLAN info in case of multiple tags. Here are some examples of the tc flower filter operations that are now supported for the IS2 VCAP: - IPv4 Addresses tc filter add dev eth12 ingress chain 8000000 prio 12 handle 12 \ protocol ip flower skip_sw dst_ip 1.0.1.1 src_ip 2.0.2.2 \ action trap - IPv6 Addresses tc filter add dev eth12 ingress chain 8000000 prio 13 handle 13 \ protocol ipv6 flower skip_sw dst_ip 1::1:1 src_ip 2::2:2 \ action trap - IPv4 fragments tc filter add dev eth12 ingress chain 8000000 prio 14 handle 14 \ protocol ip flower skip_sw dst_ip 3.0.3.3 src_ip 2.0.2.2 \ ip_flags frag/nofirstfrag action trap - TCP and UDP portnumbers tc filter add dev eth12 ingress chain 8000000 prio 21 handle 21 \ protocol ip flower skip_sw dst_ip 8.8.8.8 src_ip 2.0.2.2 \ ip_proto tcp dst_port 100 src_port 12000 action trap tc filter add dev eth12 ingress chain 8000000 prio 23 handle 23 \ protocol ipv6 flower skip_sw dst_ip 5::5:5 src_ip 2::2:2 \ ip_proto tcp dst_port 300 src_port 13000 action trap - Layer 3 and Layer 4 protocol info tc filter add dev eth12 ingress chain 8000000 prio 28 handle 28 \ protocol ipv4 flower skip_sw dst_ip 9.0.9.9 src_ip 2.0.2.2 \ ip_proto icmp action trap - VLAN tag info (outer tag) tc filter add dev eth12 ingress chain 8000000 prio 29 handle 29 \ protocol 802.1q flower skip_sw vlan_id 600 vlan_prio 6 \ vlan_ethtype ipv4 action trap tc filter add dev eth12 ingress chain 8000000 prio 31 handle 31 \ protocol 802.1q flower skip_sw vlan_id 600 vlan_prio 5 \ vlan_ethtype ipv6 action trap - TCP flags tc filter add dev eth12 ingress chain 8000000 prio 15 handle 15 \ protocol ip flower skip_sw dst_ip 4.0.4.4 src_ip 2.0.2.2 \ ip_proto tcp tcp_flags 0x2a/0x3f action trap - IP info (IPv4 TOS field) tc filter add dev eth12 ingress chain 8000000 prio 16 handle 16 \ protocol ip flower skip_sw ip_tos 0x35 dst_ip 5.0.5.5 \ src_ip 2.0.2.2 action trap The "protocol all" selection is not supported yet. Signed-off-by: Steen Hegelund --- .../microchip/sparx5/sparx5_tc_flower.c | 384 +++++++++++++++++- .../net/ethernet/microchip/vcap/vcap_api.c | 11 + .../ethernet/microchip/vcap/vcap_api_client.h | 2 + 3 files changed, 396 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c index 626558a5c850..13bc6bff4c1e 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c @@ -16,9 +16,32 @@ struct sparx5_tc_flower_parse_usage { struct flow_cls_offload *fco; struct flow_rule *frule; struct vcap_rule *vrule; + u16 l3_proto; + u8 l4_proto; unsigned int used_keys; }; +/* These protocols have dedicated keysets in IS2 and a TC dissector + * ETH_P_ARP does not have a TC dissector + */ +static u16 sparx5_tc_known_etypes[] = { + ETH_P_ALL, + ETH_P_IP, + ETH_P_IPV6, +}; + +static bool sparx5_tc_is_known_etype(u16 etype) +{ + int idx; + + /* For now this only knows about IS2 traffic classification */ + for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_known_etypes); ++idx) + if (sparx5_tc_known_etypes[idx] == etype) + return true; + + return false; +} + static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_usage *st) { enum vcap_key_field smac_key = VCAP_KF_L2_SMAC; @@ -54,9 +77,368 @@ static int sparx5_tc_flower_handler_ethaddr_usage(struct sparx5_tc_flower_parse_ return err; } +static int +sparx5_tc_flower_handler_ipv4_usage(struct sparx5_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(FLOW_DISSECTOR_KEY_IPV4_ADDRS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_ipv6_usage(struct sparx5_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(FLOW_DISSECTOR_KEY_IPV6_ADDRS); + return err; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_control_usage(struct sparx5_tc_flower_parse_usage *st) +{ + struct flow_match_control mt; + u32 value, mask; + int err = 0; + + flow_rule_match_control(st->frule, &mt); + + if (mt.mask->flags) { + if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) { + if (mt.key->flags & FLOW_DIS_FIRST_FRAG) { + value = 1; /* initial fragment */ + mask = 0x3; + } else { + if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { + value = 3; /* follow up fragment */ + mask = 0x3; + } else { + value = 0; /* no fragment */ + mask = 0x3; + } + } + } else { + if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { + value = 3; /* follow up fragment */ + mask = 0x3; + } else { + value = 0; /* no fragment */ + mask = 0x3; + } + } + + err = vcap_rule_add_key_u32(st->vrule, + VCAP_KF_L3_FRAGMENT_TYPE, + value, mask); + if (err) + goto out; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_portnum_usage(struct sparx5_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(FLOW_DISSECTOR_KEY_PORTS); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_basic_usage(struct sparx5_tc_flower_parse_usage *st) +{ + struct flow_match_basic mt; + int err = 0; + + flow_rule_match_basic(st->frule, &mt); + + if (mt.mask->n_proto) { + st->l3_proto = be16_to_cpu(mt.key->n_proto); + if (!sparx5_tc_is_known_etype(st->l3_proto)) { + err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, + st->l3_proto, ~0); + if (err) + goto out; + } else if (st->l3_proto == ETH_P_IP) { + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, + VCAP_BIT_1); + if (err) + goto out; + } else if (st->l3_proto == ETH_P_IPV6) { + err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, + VCAP_BIT_0); + if (err) + goto out; + } + } + + if (mt.mask->ip_proto) { + st->l4_proto = mt.key->ip_proto; + if (st->l4_proto == IPPROTO_TCP) { + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_TCP_IS, + VCAP_BIT_1); + if (err) + goto out; + } else if (st->l4_proto == IPPROTO_UDP) { + err = vcap_rule_add_key_bit(st->vrule, + VCAP_KF_TCP_IS, + VCAP_BIT_0); + if (err) + goto out; + } else { + err = vcap_rule_add_key_u32(st->vrule, + VCAP_KF_L3_IP_PROTO, + st->l4_proto, ~0); + if (err) + goto out; + } + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_vlan_usage(struct sparx5_tc_flower_parse_usage *st) +{ + enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; + enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; + 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; + } + + st->used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN); + + return err; +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_tcp_usage(struct sparx5_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(FLOW_DISSECTOR_KEY_TCP); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error"); + return err; +} + +static int +sparx5_tc_flower_handler_ip_usage(struct sparx5_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(FLOW_DISSECTOR_KEY_IP); + + return err; + +out: + NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error"); + return err; +} + static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_usage *st) = { - /* More dissector handlers will be added here later */ [FLOW_DISSECTOR_KEY_ETH_ADDRS] = sparx5_tc_flower_handler_ethaddr_usage, + [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = sparx5_tc_flower_handler_ipv4_usage, + [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = sparx5_tc_flower_handler_ipv6_usage, + [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage, + [FLOW_DISSECTOR_KEY_PORTS] = sparx5_tc_flower_handler_portnum_usage, + [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage, + [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage, + [FLOW_DISSECTOR_KEY_TCP] = sparx5_tc_flower_handler_tcp_usage, + [FLOW_DISSECTOR_KEY_IP] = sparx5_tc_flower_handler_ip_usage, }; static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index d255bc7deae7..ace2582d8552 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -1073,6 +1073,17 @@ int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, } EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); +/* Add a 128 bit key with value and mask to the rule */ +int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u128_key *fieldval) +{ + struct vcap_client_keyfield_data data; + + memcpy(&data.u128, fieldval, sizeof(data.u128)); + return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128); + static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, struct vcap_client_actionfield *field, struct vcap_client_actionfield_data *data) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h index 5df6808679ff..577395402a9a 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -176,6 +176,8 @@ 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, From patchwork Thu Oct 27 14:42:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steen Hegelund X-Patchwork-Id: 13022224 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 29493FA3740 for ; Thu, 27 Oct 2022 14:43:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235733AbiJ0Onh (ORCPT ); Thu, 27 Oct 2022 10:43:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235640AbiJ0Ona (ORCPT ); Thu, 27 Oct 2022 10:43:30 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 087DE18A502; Thu, 27 Oct 2022 07:43:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1666881807; x=1698417807; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NZVj8CsVcZYf/Kxg8SpnWLE0+k4rDuZWfdOpNBE1/p0=; b=MBKonXpknDmIrDMOtD18oEHepzJV2r88XPYMnyd6BtFsKcIjMrY/3Wxy DxvFDVJT5owRoR6TxiA3iFIhcYCCO8MF643XK5wT5oOUBJY/Llf0fUdCI R0+nNmpQQt6kjE5v2TIjiXEm9pRsMdB8Kq1HghBcjCZVsp06ore/GemGA 1CfgkoobGnz7vCobZMrPidq2EBoC2wEzRBiE6JOm1V/HPYZlyEuAPJ4I3 +Gjl/wrKk7dXcfZJa62WtcmBkeWfvAprUy7byeqQeNeCQQ9umbfc25kx0 DJBFSVehwKR8Y3iUr3sdXVE7O4WpsHqtgS6QfOXa6uVBqHip1B33RSvQW w==; X-IronPort-AV: E=Sophos;i="5.95,217,1661842800"; d="scan'208";a="197302458" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Oct 2022 07:43:27 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Thu, 27 Oct 2022 07:43:27 -0700 Received: from den-dk-m31857.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Thu, 27 Oct 2022 07:43:24 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Daniel Machon" , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 3/5] net: microchip: sparx5: Match keys in configured port keysets Date: Thu, 27 Oct 2022 16:42:58 +0200 Message-ID: <20221027144300.2936955-4-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027144300.2936955-1-steen.hegelund@microchip.com> References: <20221027144300.2936955-1-steen.hegelund@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This tries to match the keys in a rule with the keysets supported by the VCAP instance, and generate a list of keysets. This list is then validated against the list of keysets that is currently selected for the lookups (per port) in the VCAP configuration. The Sparx5 IS2 only has one actionset, so there is no actionset matching performed for now. Signed-off-by: Steen Hegelund --- .../microchip/sparx5/sparx5_tc_flower.c | 26 ++-- .../microchip/sparx5/sparx5_vcap_impl.c | 147 +++++++++++++++++- .../net/ethernet/microchip/vcap/vcap_api.c | 137 ++++++++++++++-- .../ethernet/microchip/vcap/vcap_api_client.h | 11 ++ 4 files changed, 298 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c index 13bc6bff4c1e..9b90e7d5517b 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c @@ -443,11 +443,13 @@ static int (*sparx5_tc_flower_usage_handlers[])(struct sparx5_tc_flower_parse_us static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, struct vcap_admin *admin, - struct vcap_rule *vrule) + struct vcap_rule *vrule, + u16 *l3_proto) { struct sparx5_tc_flower_parse_usage state = { .fco = fco, .vrule = vrule, + .l3_proto = ETH_P_ALL, }; int idx, err = 0; @@ -461,6 +463,15 @@ static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco, if (err) return err; } + + if (state.frule->match.dissector->used_keys ^ state.used_keys) { + NL_SET_ERR_MSG_MOD(fco->common.extack, + "Unsupported match item"); + return -ENOENT; + } + + if (l3_proto) + *l3_proto = state.l3_proto; return err; } @@ -473,6 +484,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, struct vcap_control *vctrl; struct flow_rule *frule; struct vcap_rule *vrule; + u16 l3_proto; int err, idx; frule = flow_cls_offload_flow_rule(fco); @@ -491,7 +503,7 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, return PTR_ERR(vrule); vrule->cookie = fco->cookie; - sparx5_tc_use_dissectors(fco, admin, vrule); + sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto); flow_action_for_each(idx, act, &frule->action) { switch (act->id) { case FLOW_ACTION_TRAP: @@ -528,14 +540,8 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, goto out; } } - /* For now the keyset is hardcoded */ - err = vcap_set_rule_set_keyset(vrule, VCAP_KFS_MAC_ETYPE); - if (err) { - NL_SET_ERR_MSG_MOD(fco->common.extack, - "No matching port keyset for filter protocol and keys"); - goto out; - } - err = vcap_val_rule(vrule, ETH_P_ALL); + /* provide the l3 protocol to guide the keyset selection */ + err = vcap_val_rule(vrule, l3_proto); if (err) { vcap_set_tc_exterr(fco, vrule); goto out; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index e4428d55af2b..642c27299e22 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -160,7 +160,7 @@ static const char *sparx5_vcap_keyset_name(struct net_device *ndev, { struct sparx5_port *port = netdev_priv(ndev); - return port->sparx5->vcap_ctrl->stats->keyfield_set_names[keyset]; + return vcap_keyset_name(port->sparx5->vcap_ctrl, keyset); } /* Check if this is the first lookup of IS2 */ @@ -204,6 +204,127 @@ static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule, vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask); } +/* Convert chain id to vcap lookup id */ +static int sparx5_vcap_cid_to_lookup(int cid) +{ + int lookup = 0; + + /* For now only handle IS2 */ + if (cid >= SPARX5_VCAP_CID_IS2_L1 && cid < SPARX5_VCAP_CID_IS2_L2) + lookup = 1; + else if (cid >= SPARX5_VCAP_CID_IS2_L2 && cid < SPARX5_VCAP_CID_IS2_L3) + lookup = 2; + else if (cid >= SPARX5_VCAP_CID_IS2_L3 && cid < SPARX5_VCAP_CID_IS2_MAX) + lookup = 3; + + return lookup; +} + +/* Return the list of keysets for the vcap port configuration */ +static int sparx5_vcap_is2_get_port_keysets(struct net_device *ndev, + int lookup, + struct vcap_keyset_list *keysetlist, + u16 l3_proto) +{ + struct sparx5_port *port = netdev_priv(ndev); + struct sparx5 *sparx5 = port->sparx5; + int portno = port->portno; + u32 value; + + /* Check if the port keyset selection is enabled */ + value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); + if (!ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_GET(value)) + return -ENOENT; + + /* Collect all keysets for the port in a list */ + if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) { + switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_ARP_MAC_ETYPE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + case VCAP_IS2_PS_ARP_ARP: + vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP); + break; + } + } + + if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) { + switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); + break; + case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); + break; + } + + switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); + break; + case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); + break; + } + } + + if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) { + switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); + break; + case VCAP_IS2_PS_IPV6_UC_IP6_STD: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD); + break; + case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); + break; + } + + switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); + break; + case VCAP_IS2_PS_IPV6_MC_IP6_STD: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD); + break; + case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER: + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); + vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); + break; + case VCAP_IS2_PS_IPV6_MC_IP6_VID: + /* Not used */ + break; + } + } + + if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP && + l3_proto != ETH_P_IPV6) { + switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) { + case VCAP_IS2_PS_NONETH_MAC_ETYPE: + /* IS2 non-classified frames generate MAC_ETYPE */ + vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); + break; + } + } + return 0; +} + /* API callback used for validating a field keyset (check the port keysets) */ static enum vcap_keyfield_set sparx5_vcap_validate_keyset(struct net_device *ndev, @@ -212,10 +333,30 @@ sparx5_vcap_validate_keyset(struct net_device *ndev, struct vcap_keyset_list *kslist, u16 l3_proto) { + struct vcap_keyset_list keysetlist = {}; + enum vcap_keyfield_set keysets[10] = {}; + int idx, jdx, lookup; + if (!kslist || kslist->cnt == 0) return VCAP_KFS_NO_VALUE; - /* for now just return whatever the API suggests */ - return kslist->keysets[0]; + + /* Get a list of currently configured keysets in the lookups */ + lookup = sparx5_vcap_cid_to_lookup(rule->vcap_chain_id); + keysetlist.max = ARRAY_SIZE(keysets); + keysetlist.keysets = keysets; + sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist, l3_proto); + + /* Check if there is a match and return the match */ + for (idx = 0; idx < kslist->cnt; ++idx) + for (jdx = 0; jdx < keysetlist.cnt; ++jdx) + if (kslist->keysets[idx] == keysets[jdx]) + return kslist->keysets[idx]; + + pr_err("%s:%d: %s not supported in port key selection\n", + __func__, __LINE__, + sparx5_vcap_keyset_name(ndev, kslist->keysets[0])); + + return -ENOENT; } /* API callback used for adding default fields to a rule */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index ace2582d8552..9e67ea814768 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -704,15 +704,115 @@ static int vcap_add_type_keyfield(struct vcap_rule *rule) return 0; } +/* Add a keyset to a keyset list */ +bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, + enum vcap_keyfield_set keyset) +{ + int idx; + + if (keysetlist->cnt < keysetlist->max) { + /* Avoid duplicates */ + for (idx = 0; idx < keysetlist->cnt; ++idx) + if (keysetlist->keysets[idx] == keyset) + return keysetlist->cnt < keysetlist->max; + keysetlist->keysets[keysetlist->cnt++] = keyset; + } + return keysetlist->cnt < keysetlist->max; +} +EXPORT_SYMBOL_GPL(vcap_keyset_list_add); + +/* map keyset id to a string with the keyset name */ +const char *vcap_keyset_name(struct vcap_control *vctrl, + enum vcap_keyfield_set keyset) +{ + return vctrl->stats->keyfield_set_names[keyset]; +} +EXPORT_SYMBOL_GPL(vcap_keyset_name); + +/* 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) +{ + return vctrl->stats->keyfield_names[key]; +} +EXPORT_SYMBOL_GPL(vcap_keyfield_name); + +/* Return the keyfield that matches a key in a keyset */ +static const struct vcap_field * +vcap_find_keyset_keyfield(struct vcap_control *vctrl, + enum vcap_type vtype, + enum vcap_keyfield_set keyset, + enum vcap_key_field key) +{ + const struct vcap_field *fields; + int idx, count; + + fields = vcap_keyfields(vctrl, vtype, keyset); + if (!fields) + return NULL; + + /* Iterate the keyfields of the keyset */ + count = vcap_keyfield_count(vctrl, vtype, keyset); + for (idx = 0; idx < count; ++idx) { + if (fields[idx].width == 0) + continue; + + if (key == idx) + return &fields[idx]; + } + + return NULL; +} + +/* Match a list of keys against the keysets available in a vcap type */ +static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri, + struct vcap_keyset_list *matches) +{ + const struct vcap_client_keyfield *ckf; + int keyset, found, keycount, map_size; + const struct vcap_field **map; + enum vcap_type vtype; + + vtype = ri->admin->vtype; + map = ri->vctrl->vcaps[vtype].keyfield_set_map; + map_size = ri->vctrl->vcaps[vtype].keyfield_set_size; + + /* Get a count of the keyfields we want to match */ + keycount = 0; + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + ++keycount; + + matches->cnt = 0; + /* Iterate the keysets of the VCAP */ + for (keyset = 0; keyset < map_size; ++keyset) { + if (!map[keyset]) + continue; + + /* Iterate the keys in the rule */ + found = 0; + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + if (vcap_find_keyset_keyfield(ri->vctrl, vtype, + keyset, ckf->ctrl.key)) + ++found; + + /* Save the keyset if all keyfields were found */ + if (found == keycount) + if (!vcap_keyset_list_add(matches, keyset)) + /* bail out when the quota is filled */ + break; + } + + return matches->cnt > 0; +} + /* Validate a rule with respect to available port keys */ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) { struct vcap_rule_internal *ri = to_intrule(rule); + struct vcap_keyset_list matches = {}; enum vcap_keyfield_set keysets[10]; - struct vcap_keyset_list kslist; int ret; - /* This validation will be much expanded later */ ret = vcap_api_check(ri->vctrl); if (ret) return ret; @@ -724,24 +824,41 @@ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) ri->data.exterr = VCAP_ERR_NO_NETDEV; return -EINVAL; } + + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); if (ri->data.keyset == VCAP_KFS_NO_VALUE) { - ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; - return -EINVAL; + /* Iterate over rule keyfields and select keysets that fits */ + if (!vcap_rule_find_keysets(ri, &matches)) { + ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; + return -EINVAL; + } + } else { + /* prepare for keyset validation */ + keysets[0] = ri->data.keyset; + matches.cnt = 1; } - /* prepare for keyset validation */ - keysets[0] = ri->data.keyset; - kslist.keysets = keysets; - kslist.cnt = 1; + /* Pick a keyset that is supported in the port lookups */ - ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, &kslist, - l3_proto); + ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, + &matches, l3_proto); if (ret < 0) { pr_err("%s:%d: keyset validation failed: %d\n", __func__, __LINE__, ret); ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; return ret; } + /* use the keyset that is supported in the port lookups */ + ret = vcap_set_rule_set_keyset(rule, ret); + if (ret < 0) { + pr_err("%s:%d: keyset was not updated: %d\n", + __func__, __LINE__, ret); + return ret; + } if (ri->data.actionset == VCAP_AFS_NO_VALUE) { + /* Later also actionsets will be matched against actions in + * the rule, and the type will be set accordingly + */ ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; return -EINVAL; } diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h index 577395402a9a..959e125baa3f 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -201,4 +201,15 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule); /* Cleanup a VCAP instance */ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin); +/* Add a keyset to a keyset list */ +bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, + enum vcap_keyfield_set keyset); + +/* map keyset id to a string with the keyset name */ +const char *vcap_keyset_name(struct vcap_control *vctrl, + enum vcap_keyfield_set keyset); +/* map key field id to a string with the key name */ +const char *vcap_keyfield_name(struct vcap_control *vctrl, + enum vcap_key_field key); + #endif /* __VCAP_API_CLIENT__ */ From patchwork Thu Oct 27 14:42:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steen Hegelund X-Patchwork-Id: 13022225 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01DE9ECAAA1 for ; Thu, 27 Oct 2022 14:44:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235580AbiJ0OoJ (ORCPT ); Thu, 27 Oct 2022 10:44:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235666AbiJ0Ong (ORCPT ); Thu, 27 Oct 2022 10:43:36 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BDFD518A53C; Thu, 27 Oct 2022 07:43:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1666881811; x=1698417811; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ra82adO9Ytf2Ct9J6Xvwy+xgtwmL2sMtcOWSaz42kuw=; b=U3OiC6VZdY6+eAsHo0KuuLtsqjyTxlchSpG1RcTNeCthGKHnvt25oMql d0/NsoGLEEmCgGRZbzVhHwHBVgDiK7s7OHyHT66bXuKldJE7oWis8BTYo 7N7cG1uue1NpecMkrqkc+wrFTmmgpbjONdS06C/QMp4xgf8/YqDD+x0ma IeH+DEkSc3OXvp1+CrPMaSqB2LpGtQN2bD8i7JLfi+UJANMDbr6f+WZjG KHCYzq2xEz1sUGk8Il/+lDQBVt++WOBws2nvYBJDM2JnsImuoZ8SbYiBx 9+Qj5gyg0U+yIQ/H6IpnR2KmoG9IQc9Txt42q9+aMbSG0ce2rWb55Wq7W A==; X-IronPort-AV: E=Sophos;i="5.95,217,1661842800"; d="scan'208";a="197302498" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Oct 2022 07:43:31 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Thu, 27 Oct 2022 07:43:30 -0700 Received: from den-dk-m31857.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Thu, 27 Oct 2022 07:43:27 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Daniel Machon" , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 4/5] net: microchip: sparx5: Let VCAP API validate added key- and actionfields Date: Thu, 27 Oct 2022 16:42:59 +0200 Message-ID: <20221027144300.2936955-5-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027144300.2936955-1-steen.hegelund@microchip.com> References: <20221027144300.2936955-1-steen.hegelund@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add support for validating keyfields and actionfields when they are added to a VCAP rule. We need to ensure that the field is not already present and that the field is in the key- or actionset, if the client has added a key- or actionset to the rule at this point. Signed-off-by: Steen Hegelund --- .../net/ethernet/microchip/vcap/vcap_api.c | 103 +++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 9e67ea814768..69ee34bb392a 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -737,6 +737,13 @@ const char *vcap_keyfield_name(struct vcap_control *vctrl, } EXPORT_SYMBOL_GPL(vcap_keyfield_name); +/* map action field id to a string with the action name */ +static const char *vcap_actionfield_name(struct vcap_control *vctrl, + enum vcap_action_field action) +{ + return vctrl->stats->actionfield_names[action]; +} + /* Return the keyfield that matches a key in a keyset */ static const struct vcap_field * vcap_find_keyset_keyfield(struct vcap_control *vctrl, @@ -1109,14 +1116,60 @@ static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, memcpy(&field->data, data, sizeof(field->data)); } +/* Check if the keyfield is already in the rule */ +static bool vcap_keyfield_unique(struct vcap_rule *rule, + enum vcap_key_field key) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_client_keyfield *ckf; + + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + if (ckf->ctrl.key == key) + return false; + return true; +} + +/* Check if the keyfield is in the keyset */ +static bool vcap_keyfield_match_keyset(struct vcap_rule *rule, + enum vcap_key_field key) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_keyfield_set keyset = rule->keyset; + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + + /* the field is accepted if the rule has no keyset yet */ + if (keyset == VCAP_KFS_NO_VALUE) + return true; + fields = vcap_keyfields(ri->vctrl, vt, keyset); + if (!fields) + return false; + /* if there is a width there is a way */ + return fields[key].width > 0; +} + static int vcap_rule_add_key(struct vcap_rule *rule, enum vcap_key_field key, enum vcap_field_type ftype, struct vcap_client_keyfield_data *data) { + struct vcap_rule_internal *ri = to_intrule(rule); struct vcap_client_keyfield *field; - /* More validation will be added here later */ + if (!vcap_keyfield_unique(rule, key)) { + pr_warn("%s:%d: keyfield %s is already in the rule\n", + __func__, __LINE__, + vcap_keyfield_name(ri->vctrl, key)); + return -EINVAL; + } + + if (!vcap_keyfield_match_keyset(rule, key)) { + pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n", + __func__, __LINE__, + vcap_keyfield_name(ri->vctrl, key)); + return -EINVAL; + } + field = kzalloc(sizeof(*field), GFP_KERNEL); if (!field) return -ENOMEM; @@ -1209,14 +1262,60 @@ static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, memcpy(&field->data, data, sizeof(field->data)); } +/* Check if the actionfield is already in the rule */ +static bool vcap_actionfield_unique(struct vcap_rule *rule, + enum vcap_action_field act) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_client_actionfield *caf; + + list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) + if (caf->ctrl.action == act) + return false; + return true; +} + +/* Check if the actionfield is in the actionset */ +static bool vcap_actionfield_match_actionset(struct vcap_rule *rule, + enum vcap_action_field action) +{ + enum vcap_actionfield_set actionset = rule->actionset; + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + + /* the field is accepted if the rule has no actionset yet */ + if (actionset == VCAP_AFS_NO_VALUE) + return true; + fields = vcap_actionfields(ri->vctrl, vt, actionset); + if (!fields) + return false; + /* if there is a width there is a way */ + return fields[action].width > 0; +} + static int vcap_rule_add_action(struct vcap_rule *rule, enum vcap_action_field action, enum vcap_field_type ftype, struct vcap_client_actionfield_data *data) { + struct vcap_rule_internal *ri = to_intrule(rule); struct vcap_client_actionfield *field; - /* More validation will be added here later */ + if (!vcap_actionfield_unique(rule, action)) { + pr_warn("%s:%d: actionfield %s is already in the rule\n", + __func__, __LINE__, + vcap_actionfield_name(ri->vctrl, action)); + return -EINVAL; + } + + if (!vcap_actionfield_match_actionset(rule, action)) { + pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n", + __func__, __LINE__, + vcap_actionfield_name(ri->vctrl, action)); + return -EINVAL; + } + field = kzalloc(sizeof(*field), GFP_KERNEL); if (!field) return -ENOMEM; From patchwork Thu Oct 27 14:43:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steen Hegelund X-Patchwork-Id: 13022226 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 14E68FA3741 for ; Thu, 27 Oct 2022 14:44:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235708AbiJ0OoK (ORCPT ); Thu, 27 Oct 2022 10:44:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54610 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235819AbiJ0OoB (ORCPT ); Thu, 27 Oct 2022 10:44:01 -0400 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5689A18BE0B; Thu, 27 Oct 2022 07:43:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1666881820; x=1698417820; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=I5LWEbSZNd+nZYoMdomCoEWY69gDQcVpzwV61UXy/Vk=; b=TFXl35iTS0DXuLineWLgFjH/eKJwCszXW2ZKHhUkuYIOdxpY0g8lka8k Ib/I7NaThXmcaqxPRIIiJr3b1Tab/o3tTQ3c8t4MEcdbQwODMXd4FBI7s oJgFRSy3C+ri82PbLtoI560EB2IF4irdGpJohGEtaebqpq3sgLi9BTnR1 qfAxAw69Jp3qzWv3EcHz5UNpNxDBD902Ay1qX74z78xTq6I2wYk3ePVQs 6RI0tsBuUxneChvHTXUzG+dtl0EzLHpRVUuoH8ah1YKDDMXBPaVZ4UnYv izQIzoHdKo1VAyLl2t+qtqs/l7YnK0XqRr84xkx/N+cb35oEPPi8MNvfO A==; X-IronPort-AV: E=Sophos;i="5.95,217,1661842800"; d="scan'208";a="120642710" Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 27 Oct 2022 07:43:39 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.12; Thu, 27 Oct 2022 07:43:33 -0700 Received: from den-dk-m31857.microchip.com (10.10.115.15) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.12 via Frontend Transport; Thu, 27 Oct 2022 07:43:30 -0700 From: Steen Hegelund To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni CC: Steen Hegelund , , Randy Dunlap , "Casper Andersson" , Russell King , Wan Jiabing , "Nathan Huckleberry" , , , , "Daniel Machon" , Horatiu Vultur , Lars Povlsen Subject: [PATCH net-next 5/5] net: microchip: sparx5: Adding KUNIT tests of key/action values in VCAP API Date: Thu, 27 Oct 2022 16:43:00 +0200 Message-ID: <20221027144300.2936955-6-steen.hegelund@microchip.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221027144300.2936955-1-steen.hegelund@microchip.com> References: <20221027144300.2936955-1-steen.hegelund@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This tests that the available keyfield and actionfield add methods are doing the exepected work: adding the value (and mask) to the keyfield/actionfield list item in the rule. The test also covers the functionality that matches a rule to a keyset. Signed-off-by: Steen Hegelund --- .../ethernet/microchip/vcap/vcap_api_kunit.c | 406 ++++++++++++++++++ 1 file changed, 406 insertions(+) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index b01a6e5039b0..2141d62e62bb 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -22,6 +22,7 @@ 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 = {}; /* Callback used by the VCAP API */ static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev, @@ -904,6 +905,409 @@ static void vcap_api_encode_rule_actionset_test(struct kunit *test) KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[11]); } +static void vcap_api_rule_add_keyvalue_test(struct kunit *test) +{ + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .data = { + .keyset = VCAP_KFS_NO_VALUE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_rule *rule = (struct vcap_rule *)&ri; + struct vcap_client_keyfield *kf; + int ret; + struct vcap_u128_key dip = { + .value = {0x17, 0x26, 0x35, 0x44, 0x63, 0x62, 0x71}, + .mask = {0xf1, 0xf2, 0xf3, 0xf4, 0x4f, 0x3f, 0x2f, 0x1f}, + }; + int idx; + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, + VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 0x98765432, 0xff00ffab); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_TYPE, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x98765432, kf->data.u32.value); + KUNIT_EXPECT_EQ(test, 0xff00ffab, kf->data.u32.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_u128(rule, VCAP_KF_L3_IP6_SIP, &dip); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_L3_IP6_SIP, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U128, kf->ctrl.type); + for (idx = 0; idx < ARRAY_SIZE(dip.value); ++idx) + KUNIT_EXPECT_EQ(test, dip.value[idx], kf->data.u128.value[idx]); + for (idx = 0; idx < ARRAY_SIZE(dip.mask); ++idx) + KUNIT_EXPECT_EQ(test, dip.mask[idx], kf->data.u128.mask[idx]); +} + +static void vcap_api_rule_add_actionvalue_test(struct kunit *test) +{ + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .data = { + .actionset = VCAP_AFS_NO_VALUE, + }, + }; + struct vcap_rule *rule = (struct vcap_rule *)&ri; + struct vcap_client_actionfield *af; + int ret; + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_0); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x1, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE, 0x98765432); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_TYPE, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x98765432, af->data.u32.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MASK_MODE, 0xaabbccdd); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_MASK_MODE, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0xaabbccdd, af->data.u32.value); +} + +static void vcap_api_rule_find_keyset_test(struct kunit *test) +{ + struct vcap_keyset_list matches = {}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf_1[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_L3, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_RNG, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK, + }, { + .ctrl.key = VCAP_KF_L2_DMAC, + }, { + .ctrl.key = VCAP_KF_ETYPE_LEN_IS, + }, { + .ctrl.key = VCAP_KF_ETYPE, + }, + }; + struct vcap_client_keyfield ckf_2[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_ARP_OPCODE, + }, { + .ctrl.key = VCAP_KF_L3_IP4_SIP, + }, { + .ctrl.key = VCAP_KF_L3_IP4_DIP, + }, { + .ctrl.key = VCAP_KF_8021Q_PCP_CLS, + }, { + .ctrl.key = VCAP_KF_ETYPE_LEN_IS, /* Not with ARP */ + }, { + .ctrl.key = VCAP_KF_ETYPE, /* Not with ARP */ + }, + }; + struct vcap_client_keyfield ckf_3[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_8021Q_DEI_CLS, + }, { + .ctrl.key = VCAP_KF_8021Q_PCP_CLS, + }, { + .ctrl.key = VCAP_KF_8021Q_VID_CLS, + }, { + .ctrl.key = VCAP_KF_ISDX_CLS, + }, { + .ctrl.key = VCAP_KF_L2_MC_IS, + }, { + .ctrl.key = VCAP_KF_L2_BC_IS, + }, + }; + int idx; + bool ret; + enum vcap_keyfield_set keysets[10] = {0}; + + INIT_LIST_HEAD(&ri.data.keyfields); + for (idx = 0; idx < ARRAY_SIZE(ckf_1); idx++) + list_add_tail(&ckf_1[idx].ctrl.list, &ri.data.keyfields); + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); + memset(keysets, 0, sizeof(keysets)); + + ret = vcap_rule_find_keysets(&ri, &matches); + KUNIT_EXPECT_EQ(test, true, ret); + KUNIT_EXPECT_EQ(test, 1, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, matches.keysets[0]); + + INIT_LIST_HEAD(&ri.data.keyfields); + for (idx = 0; idx < ARRAY_SIZE(ckf_2); idx++) + list_add_tail(&ckf_2[idx].ctrl.list, &ri.data.keyfields); + memset(keysets, 0, sizeof(keysets)); + ret = vcap_rule_find_keysets(&ri, &matches); + KUNIT_EXPECT_EQ(test, false, ret); + KUNIT_EXPECT_EQ(test, 0, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_NO_VALUE, matches.keysets[0]); + + INIT_LIST_HEAD(&ri.data.keyfields); + for (idx = 0; idx < ARRAY_SIZE(ckf_3); idx++) + list_add_tail(&ckf_3[idx].ctrl.list, &ri.data.keyfields); + memset(keysets, 0, sizeof(keysets)); + ret = vcap_rule_find_keysets(&ri, &matches); + KUNIT_EXPECT_EQ(test, true, ret); + KUNIT_EXPECT_EQ(test, 6, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_ARP, matches.keysets[0]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP4_OTHER, matches.keysets[1]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP4_TCP_UDP, matches.keysets[2]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP6_STD, matches.keysets[3]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP_7TUPLE, matches.keysets[4]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, matches.keysets[5]); +} + +static void vcap_api_encode_rule_test(struct kunit *test) +{ + /* Data used by VCAP Library callback */ + static u32 keydata[32] = {}; + static u32 mskdata[32] = {}; + static u32 actdata[32] = {}; + + struct vcap_admin is2_admin = { + .vtype = VCAP_TYPE_IS2, + .first_cid = 10000, + .last_cid = 19999, + .lookups = 4, + .last_valid_addr = 3071, + .first_valid_addr = 0, + .last_used_addr = 800, + .cache = { + .keystream = keydata, + .maskstream = mskdata, + .actionstream = actdata, + }, + }; + struct vcap_rule *rule = 0; + struct vcap_rule_internal *ri = 0; + int vcap_chain_id = 10005; + enum vcap_user user = VCAP_USER_VCAP_UTIL; + u16 priority = 10; + int id = 100; + int ret; + struct vcap_u48_key smac = { + .value = { 0x88, 0x75, 0x32, 0x34, 0x9e, 0xb1 }, + .mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + struct vcap_u48_key dmac = { + .value = { 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }, + .mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + u32 port_mask_rng_value = 0x05; + u32 port_mask_rng_mask = 0x0f; + u32 igr_port_mask_value = 0xffabcd01; + u32 igr_port_mask_mask = ~0; + /* counter is not written yet, so it is not in expwriteaddr */ + u32 expwriteaddr[] = {792, 793, 794, 795, 796, 797, 0}; + int idx; + + vcap_test_api_init(&is2_admin); + + /* Allocate the rule */ + rule = vcap_alloc_rule(&test_vctrl, &test_netdev, vcap_chain_id, user, + priority, id); + KUNIT_EXPECT_PTR_NE(test, NULL, rule); + ri = (struct vcap_rule_internal *)rule; + + /* Add rule keys */ + ret = vcap_rule_add_key_u48(rule, VCAP_KF_L2_DMAC, &dmac); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u48(rule, VCAP_KF_L2_SMAC, &smac); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_ETYPE_LEN_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + /* Cannot add the same field twice */ + ret = vcap_rule_add_key_bit(rule, VCAP_KF_ETYPE_LEN_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_IF_IGR_PORT_MASK_L3, + VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, + port_mask_rng_value, port_mask_rng_mask); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, + igr_port_mask_value, igr_port_mask_mask); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* Add rule actions */ + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_CNT_ID, id); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MATCH_ID, 1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MATCH_ID_MASK, 1); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* For now the actionset is hardcoded */ + ret = vcap_set_rule_set_actionset(rule, VCAP_AFS_BASE_TYPE); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* Validation with validate keyset callback */ + ret = vcap_val_rule(rule, ETH_P_ALL); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, rule->keyset); + KUNIT_EXPECT_EQ(test, VCAP_AFS_BASE_TYPE, rule->actionset); + KUNIT_EXPECT_EQ(test, 6, ri->size); + KUNIT_EXPECT_EQ(test, 2, ri->keyset_sw_regs); + KUNIT_EXPECT_EQ(test, 4, ri->actionset_sw_regs); + + /* Add rule with write callback */ + ret = vcap_add_rule(rule); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, 792, is2_admin.last_used_addr); + for (idx = 0; idx < ARRAY_SIZE(expwriteaddr); ++idx) + KUNIT_EXPECT_EQ(test, expwriteaddr[idx], test_updateaddr[idx]); + + /* Check that the rule has been added */ + ret = list_empty(&is2_admin.rules); + KUNIT_EXPECT_EQ(test, false, ret); + KUNIT_EXPECT_EQ(test, 0, ret); + vcap_free_rule(rule); + + /* Check that the rule has been freed: tricky to access since this + * memory should not be accessible anymore + */ + KUNIT_EXPECT_PTR_NE(test, NULL, rule); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, true, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, true, ret); +} + +static struct kunit_case vcap_api_full_rule_test_cases[] = { + KUNIT_CASE(vcap_api_rule_find_keyset_test), + KUNIT_CASE(vcap_api_encode_rule_test), + {} +}; + +static struct kunit_suite vcap_api_full_rule_test_suite = { + .name = "VCAP_API_Full_Rule_Testsuite", + .test_cases = vcap_api_full_rule_test_cases, +}; + +static struct kunit_case vcap_api_rule_value_test_cases[] = { + KUNIT_CASE(vcap_api_rule_add_keyvalue_test), + KUNIT_CASE(vcap_api_rule_add_actionvalue_test), + {} +}; + +static struct kunit_suite vcap_api_rule_value_test_suite = { + .name = "VCAP_API_Rule_Value_Testsuite", + .test_cases = vcap_api_rule_value_test_cases, +}; + static struct kunit_case vcap_api_encoding_test_cases[] = { KUNIT_CASE(vcap_api_set_bit_1_test), KUNIT_CASE(vcap_api_set_bit_0_test), @@ -930,4 +1334,6 @@ static struct kunit_suite vcap_api_encoding_test_suite = { .test_cases = vcap_api_encoding_test_cases, }; +kunit_test_suite(vcap_api_full_rule_test_suite); +kunit_test_suite(vcap_api_rule_value_test_suite); kunit_test_suite(vcap_api_encoding_test_suite);