12e99ea80SHyong Youb Kim /* SPDX-License-Identifier: BSD-3-Clause 22e99ea80SHyong Youb Kim * Copyright 2008-2017 Cisco Systems, Inc. All rights reserved. 30f766680SJohn Daley */ 40f766680SJohn Daley 50f766680SJohn Daley #include <errno.h> 6cc17feb9SAdrien Mazarguil #include <stdint.h> 70f766680SJohn Daley #include <rte_log.h> 8df96fd0dSBruce Richardson #include <ethdev_driver.h> 90f766680SJohn Daley #include <rte_flow_driver.h> 100f766680SJohn Daley #include <rte_ether.h> 110f766680SJohn Daley #include <rte_ip.h> 120f766680SJohn Daley #include <rte_udp.h> 130f766680SJohn Daley 140f766680SJohn Daley #include "enic_compat.h" 150f766680SJohn Daley #include "enic.h" 160f766680SJohn Daley #include "vnic_dev.h" 170f766680SJohn Daley #include "vnic_nic.h" 180f766680SJohn Daley 1960c6acb4SHyong Youb Kim /* 2060c6acb4SHyong Youb Kim * Common arguments passed to copy_item functions. Use this structure 2160c6acb4SHyong Youb Kim * so we can easily add new arguments. 2260c6acb4SHyong Youb Kim * item: Item specification. 2360c6acb4SHyong Youb Kim * filter: Partially filled in NIC filter structure. 2460c6acb4SHyong Youb Kim * inner_ofst: If zero, this is an outer header. If non-zero, this is 2560c6acb4SHyong Youb Kim * the offset into L5 where the header begins. 264445a0f4SHyong Youb Kim * l2_proto_off: offset to EtherType eth or vlan header. 274445a0f4SHyong Youb Kim * l3_proto_off: offset to next protocol field in IPv4 or 6 header. 2860c6acb4SHyong Youb Kim */ 2960c6acb4SHyong Youb Kim struct copy_item_args { 3060c6acb4SHyong Youb Kim const struct rte_flow_item *item; 3160c6acb4SHyong Youb Kim struct filter_v2 *filter; 3260c6acb4SHyong Youb Kim uint8_t *inner_ofst; 334445a0f4SHyong Youb Kim uint8_t l2_proto_off; 344445a0f4SHyong Youb Kim uint8_t l3_proto_off; 356e54c8acSHyong Youb Kim struct enic *enic; 3660c6acb4SHyong Youb Kim }; 3760c6acb4SHyong Youb Kim 3860c6acb4SHyong Youb Kim /* functions for copying items into enic filters */ 3960c6acb4SHyong Youb Kim typedef int (enic_copy_item_fn)(struct copy_item_args *arg); 4060c6acb4SHyong Youb Kim 416ced1376SJohn Daley /** Info about how to copy items into enic filters. */ 426ced1376SJohn Daley struct enic_items { 436ced1376SJohn Daley /** Function for copying and validating an item. */ 4460c6acb4SHyong Youb Kim enic_copy_item_fn *copy_item; 456ced1376SJohn Daley /** List of valid previous items. */ 466ced1376SJohn Daley const enum rte_flow_item_type * const prev_items; 476ced1376SJohn Daley /** True if it's OK for this item to be the first item. For some NIC 486ced1376SJohn Daley * versions, it's invalid to start the stack above layer 3. 496ced1376SJohn Daley */ 5004e8ec74SJohn Daley const uint8_t valid_start_item; 514445a0f4SHyong Youb Kim /* Inner packet version of copy_item. */ 524445a0f4SHyong Youb Kim enic_copy_item_fn *inner_copy_item; 536ced1376SJohn Daley }; 546ced1376SJohn Daley 556ced1376SJohn Daley /** Filtering capabilities for various NIC and firmware versions. */ 566ced1376SJohn Daley struct enic_filter_cap { 576ced1376SJohn Daley /** list of valid items and their handlers and attributes. */ 586ced1376SJohn Daley const struct enic_items *item_info; 594d8e9aa4SHyong Youb Kim /* Max type in the above list, used to detect unsupported types */ 604d8e9aa4SHyong Youb Kim enum rte_flow_item_type max_item_type; 616ced1376SJohn Daley }; 626ced1376SJohn Daley 636ced1376SJohn Daley /* functions for copying flow actions into enic actions */ 64e9434f6fSHyong Youb Kim typedef int (copy_action_fn)(struct enic *enic, 65e9434f6fSHyong Youb Kim const struct rte_flow_action actions[], 666ced1376SJohn Daley struct filter_action_v2 *enic_action); 676ced1376SJohn Daley 686ced1376SJohn Daley /** Action capabilities for various NICs. */ 696ced1376SJohn Daley struct enic_action_cap { 706ced1376SJohn Daley /** list of valid actions */ 716ced1376SJohn Daley const enum rte_flow_action_type *actions; 726ced1376SJohn Daley /** copy function for a particular NIC */ 73e9434f6fSHyong Youb Kim copy_action_fn *copy_fn; 746ced1376SJohn Daley }; 756ced1376SJohn Daley 766ced1376SJohn Daley /* Forward declarations */ 77aa3d2ff8SJohn Daley static enic_copy_item_fn enic_copy_item_ipv4_v1; 78aa3d2ff8SJohn Daley static enic_copy_item_fn enic_copy_item_udp_v1; 79aa3d2ff8SJohn Daley static enic_copy_item_fn enic_copy_item_tcp_v1; 80477959e6SHyong Youb Kim static enic_copy_item_fn enic_copy_item_raw_v2; 816ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_eth_v2; 826ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_vlan_v2; 836ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_ipv4_v2; 846ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_ipv6_v2; 856ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_udp_v2; 866ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_tcp_v2; 876ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_sctp_v2; 886ced1376SJohn Daley static enic_copy_item_fn enic_copy_item_vxlan_v2; 894445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_eth_v2; 904445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_vlan_v2; 914445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_ipv4_v2; 924445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_ipv6_v2; 934445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_udp_v2; 944445a0f4SHyong Youb Kim static enic_copy_item_fn enic_copy_item_inner_tcp_v2; 9526faa126SJohn Daley static copy_action_fn enic_copy_action_v1; 966ced1376SJohn Daley static copy_action_fn enic_copy_action_v2; 976ced1376SJohn Daley 9826faa126SJohn Daley /** 99aa3d2ff8SJohn Daley * Legacy NICs or NICs with outdated firmware. Only 5-tuple perfect match 100aa3d2ff8SJohn Daley * is supported. 101aa3d2ff8SJohn Daley */ 102aa3d2ff8SJohn Daley static const struct enic_items enic_items_v1[] = { 103aa3d2ff8SJohn Daley [RTE_FLOW_ITEM_TYPE_IPV4] = { 104aa3d2ff8SJohn Daley .copy_item = enic_copy_item_ipv4_v1, 105aa3d2ff8SJohn Daley .valid_start_item = 1, 106aa3d2ff8SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 107aa3d2ff8SJohn Daley RTE_FLOW_ITEM_TYPE_END, 108aa3d2ff8SJohn Daley }, 1094445a0f4SHyong Youb Kim .inner_copy_item = NULL, 110aa3d2ff8SJohn Daley }, 111aa3d2ff8SJohn Daley [RTE_FLOW_ITEM_TYPE_UDP] = { 112aa3d2ff8SJohn Daley .copy_item = enic_copy_item_udp_v1, 113aa3d2ff8SJohn Daley .valid_start_item = 0, 114aa3d2ff8SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 115aa3d2ff8SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 116aa3d2ff8SJohn Daley RTE_FLOW_ITEM_TYPE_END, 117aa3d2ff8SJohn Daley }, 1184445a0f4SHyong Youb Kim .inner_copy_item = NULL, 119aa3d2ff8SJohn Daley }, 120aa3d2ff8SJohn Daley [RTE_FLOW_ITEM_TYPE_TCP] = { 121aa3d2ff8SJohn Daley .copy_item = enic_copy_item_tcp_v1, 122aa3d2ff8SJohn Daley .valid_start_item = 0, 123aa3d2ff8SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 124aa3d2ff8SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 125aa3d2ff8SJohn Daley RTE_FLOW_ITEM_TYPE_END, 126aa3d2ff8SJohn Daley }, 1274445a0f4SHyong Youb Kim .inner_copy_item = NULL, 128aa3d2ff8SJohn Daley }, 129aa3d2ff8SJohn Daley }; 130aa3d2ff8SJohn Daley 131aa3d2ff8SJohn Daley /** 13226faa126SJohn Daley * NICs have Advanced Filters capability but they are disabled. This means 13326faa126SJohn Daley * that layer 3 must be specified. 13426faa126SJohn Daley */ 13526faa126SJohn Daley static const struct enic_items enic_items_v2[] = { 136477959e6SHyong Youb Kim [RTE_FLOW_ITEM_TYPE_RAW] = { 137477959e6SHyong Youb Kim .copy_item = enic_copy_item_raw_v2, 138477959e6SHyong Youb Kim .valid_start_item = 0, 139477959e6SHyong Youb Kim .prev_items = (const enum rte_flow_item_type[]) { 140477959e6SHyong Youb Kim RTE_FLOW_ITEM_TYPE_UDP, 141477959e6SHyong Youb Kim RTE_FLOW_ITEM_TYPE_END, 142477959e6SHyong Youb Kim }, 1434445a0f4SHyong Youb Kim .inner_copy_item = NULL, 144477959e6SHyong Youb Kim }, 14526faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_ETH] = { 14626faa126SJohn Daley .copy_item = enic_copy_item_eth_v2, 14726faa126SJohn Daley .valid_start_item = 1, 14826faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 14926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_VXLAN, 15026faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 15126faa126SJohn Daley }, 1524445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_eth_v2, 15326faa126SJohn Daley }, 15426faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_VLAN] = { 15526faa126SJohn Daley .copy_item = enic_copy_item_vlan_v2, 15626faa126SJohn Daley .valid_start_item = 1, 15726faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 15826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 15926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 16026faa126SJohn Daley }, 1614445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_vlan_v2, 16226faa126SJohn Daley }, 16326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_IPV4] = { 16426faa126SJohn Daley .copy_item = enic_copy_item_ipv4_v2, 16526faa126SJohn Daley .valid_start_item = 1, 16626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 16726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 16826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_VLAN, 16926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 17026faa126SJohn Daley }, 1714445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_ipv4_v2, 17226faa126SJohn Daley }, 17326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_IPV6] = { 17426faa126SJohn Daley .copy_item = enic_copy_item_ipv6_v2, 17526faa126SJohn Daley .valid_start_item = 1, 17626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 17726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 17826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_VLAN, 17926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 18026faa126SJohn Daley }, 1814445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_ipv6_v2, 18226faa126SJohn Daley }, 18326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_UDP] = { 18426faa126SJohn Daley .copy_item = enic_copy_item_udp_v2, 18526faa126SJohn Daley .valid_start_item = 0, 18626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 18726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 18826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 18926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 19026faa126SJohn Daley }, 1914445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_udp_v2, 19226faa126SJohn Daley }, 19326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_TCP] = { 19426faa126SJohn Daley .copy_item = enic_copy_item_tcp_v2, 19526faa126SJohn Daley .valid_start_item = 0, 19626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 19726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 19826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 19926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 20026faa126SJohn Daley }, 2014445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_tcp_v2, 20226faa126SJohn Daley }, 20326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_SCTP] = { 20426faa126SJohn Daley .copy_item = enic_copy_item_sctp_v2, 20526faa126SJohn Daley .valid_start_item = 0, 20626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 20726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 20826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 20926faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 21026faa126SJohn Daley }, 2114445a0f4SHyong Youb Kim .inner_copy_item = NULL, 21226faa126SJohn Daley }, 21326faa126SJohn Daley [RTE_FLOW_ITEM_TYPE_VXLAN] = { 21426faa126SJohn Daley .copy_item = enic_copy_item_vxlan_v2, 21526faa126SJohn Daley .valid_start_item = 0, 21626faa126SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 21726faa126SJohn Daley RTE_FLOW_ITEM_TYPE_UDP, 21826faa126SJohn Daley RTE_FLOW_ITEM_TYPE_END, 21926faa126SJohn Daley }, 2204445a0f4SHyong Youb Kim .inner_copy_item = NULL, 22126faa126SJohn Daley }, 22226faa126SJohn Daley }; 22326faa126SJohn Daley 2246ced1376SJohn Daley /** NICs with Advanced filters enabled */ 2256ced1376SJohn Daley static const struct enic_items enic_items_v3[] = { 226477959e6SHyong Youb Kim [RTE_FLOW_ITEM_TYPE_RAW] = { 227477959e6SHyong Youb Kim .copy_item = enic_copy_item_raw_v2, 228477959e6SHyong Youb Kim .valid_start_item = 0, 229477959e6SHyong Youb Kim .prev_items = (const enum rte_flow_item_type[]) { 230477959e6SHyong Youb Kim RTE_FLOW_ITEM_TYPE_UDP, 231477959e6SHyong Youb Kim RTE_FLOW_ITEM_TYPE_END, 232477959e6SHyong Youb Kim }, 2334445a0f4SHyong Youb Kim .inner_copy_item = NULL, 234477959e6SHyong Youb Kim }, 2356ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_ETH] = { 2366ced1376SJohn Daley .copy_item = enic_copy_item_eth_v2, 2376ced1376SJohn Daley .valid_start_item = 1, 2386ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2396ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_VXLAN, 2406ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2416ced1376SJohn Daley }, 2424445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_eth_v2, 2436ced1376SJohn Daley }, 2446ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_VLAN] = { 2456ced1376SJohn Daley .copy_item = enic_copy_item_vlan_v2, 2466ced1376SJohn Daley .valid_start_item = 1, 2476ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2486ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 2496ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2506ced1376SJohn Daley }, 2514445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_vlan_v2, 2526ced1376SJohn Daley }, 2536ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_IPV4] = { 2546ced1376SJohn Daley .copy_item = enic_copy_item_ipv4_v2, 2556ced1376SJohn Daley .valid_start_item = 1, 2566ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2576ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 2586ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_VLAN, 2596ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2606ced1376SJohn Daley }, 2614445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_ipv4_v2, 2626ced1376SJohn Daley }, 2636ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_IPV6] = { 2646ced1376SJohn Daley .copy_item = enic_copy_item_ipv6_v2, 2656ced1376SJohn Daley .valid_start_item = 1, 2666ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2676ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_ETH, 2686ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_VLAN, 2696ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2706ced1376SJohn Daley }, 2714445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_ipv6_v2, 2726ced1376SJohn Daley }, 2736ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_UDP] = { 2746ced1376SJohn Daley .copy_item = enic_copy_item_udp_v2, 2756ced1376SJohn Daley .valid_start_item = 1, 2766ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2776ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 2786ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 2796ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2806ced1376SJohn Daley }, 2814445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_udp_v2, 2826ced1376SJohn Daley }, 2836ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_TCP] = { 2846ced1376SJohn Daley .copy_item = enic_copy_item_tcp_v2, 2856ced1376SJohn Daley .valid_start_item = 1, 2866ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2876ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 2886ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 2896ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 2906ced1376SJohn Daley }, 2914445a0f4SHyong Youb Kim .inner_copy_item = enic_copy_item_inner_tcp_v2, 2926ced1376SJohn Daley }, 2936ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_SCTP] = { 2946ced1376SJohn Daley .copy_item = enic_copy_item_sctp_v2, 2953a1c3cd0SHyong Youb Kim .valid_start_item = 0, 2966ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 2976ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV4, 2986ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_IPV6, 2996ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 3006ced1376SJohn Daley }, 3014445a0f4SHyong Youb Kim .inner_copy_item = NULL, 3026ced1376SJohn Daley }, 3036ced1376SJohn Daley [RTE_FLOW_ITEM_TYPE_VXLAN] = { 3046ced1376SJohn Daley .copy_item = enic_copy_item_vxlan_v2, 3056ced1376SJohn Daley .valid_start_item = 1, 3066ced1376SJohn Daley .prev_items = (const enum rte_flow_item_type[]) { 3076ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_UDP, 3086ced1376SJohn Daley RTE_FLOW_ITEM_TYPE_END, 3096ced1376SJohn Daley }, 3104445a0f4SHyong Youb Kim .inner_copy_item = NULL, 3116ced1376SJohn Daley }, 3126ced1376SJohn Daley }; 3136ced1376SJohn Daley 3146ced1376SJohn Daley /** Filtering capabilities indexed this NICs supported filter type. */ 3156ced1376SJohn Daley static const struct enic_filter_cap enic_filter_cap[] = { 316aa3d2ff8SJohn Daley [FILTER_IPV4_5TUPLE] = { 317aa3d2ff8SJohn Daley .item_info = enic_items_v1, 3184d8e9aa4SHyong Youb Kim .max_item_type = RTE_FLOW_ITEM_TYPE_TCP, 319aa3d2ff8SJohn Daley }, 32026faa126SJohn Daley [FILTER_USNIC_IP] = { 32126faa126SJohn Daley .item_info = enic_items_v2, 3224d8e9aa4SHyong Youb Kim .max_item_type = RTE_FLOW_ITEM_TYPE_VXLAN, 32326faa126SJohn Daley }, 3246ced1376SJohn Daley [FILTER_DPDK_1] = { 3256ced1376SJohn Daley .item_info = enic_items_v3, 3264d8e9aa4SHyong Youb Kim .max_item_type = RTE_FLOW_ITEM_TYPE_VXLAN, 3276ced1376SJohn Daley }, 3286ced1376SJohn Daley }; 3296ced1376SJohn Daley 33026faa126SJohn Daley /** Supported actions for older NICs */ 33126faa126SJohn Daley static const enum rte_flow_action_type enic_supported_actions_v1[] = { 33226faa126SJohn Daley RTE_FLOW_ACTION_TYPE_QUEUE, 33326faa126SJohn Daley RTE_FLOW_ACTION_TYPE_END, 33426faa126SJohn Daley }; 33526faa126SJohn Daley 3366ced1376SJohn Daley /** Supported actions for newer NICs */ 337036c545dSHyong Youb Kim static const enum rte_flow_action_type enic_supported_actions_v2_id[] = { 3386ced1376SJohn Daley RTE_FLOW_ACTION_TYPE_QUEUE, 3396ced1376SJohn Daley RTE_FLOW_ACTION_TYPE_MARK, 3406ced1376SJohn Daley RTE_FLOW_ACTION_TYPE_FLAG, 341e9434f6fSHyong Youb Kim RTE_FLOW_ACTION_TYPE_RSS, 3425af7af4dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_PASSTHRU, 3436ced1376SJohn Daley RTE_FLOW_ACTION_TYPE_END, 3446ced1376SJohn Daley }; 3456ced1376SJohn Daley 346036c545dSHyong Youb Kim static const enum rte_flow_action_type enic_supported_actions_v2_drop[] = { 347036c545dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_QUEUE, 348036c545dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_MARK, 349036c545dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_FLAG, 350036c545dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_DROP, 351e9434f6fSHyong Youb Kim RTE_FLOW_ACTION_TYPE_RSS, 3525af7af4dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_PASSTHRU, 353036c545dSHyong Youb Kim RTE_FLOW_ACTION_TYPE_END, 354036c545dSHyong Youb Kim }; 355036c545dSHyong Youb Kim 3566ced1376SJohn Daley /** Action capabilities indexed by NIC version information */ 3576ced1376SJohn Daley static const struct enic_action_cap enic_action_cap[] = { 35826faa126SJohn Daley [FILTER_ACTION_RQ_STEERING_FLAG] = { 35926faa126SJohn Daley .actions = enic_supported_actions_v1, 36026faa126SJohn Daley .copy_fn = enic_copy_action_v1, 36126faa126SJohn Daley }, 362036c545dSHyong Youb Kim [FILTER_ACTION_FILTER_ID_FLAG] = { 363036c545dSHyong Youb Kim .actions = enic_supported_actions_v2_id, 364036c545dSHyong Youb Kim .copy_fn = enic_copy_action_v2, 365036c545dSHyong Youb Kim }, 366036c545dSHyong Youb Kim [FILTER_ACTION_DROP_FLAG] = { 367036c545dSHyong Youb Kim .actions = enic_supported_actions_v2_drop, 3686ced1376SJohn Daley .copy_fn = enic_copy_action_v2, 3696ced1376SJohn Daley }, 3706ced1376SJohn Daley }; 371aa3d2ff8SJohn Daley 372aa3d2ff8SJohn Daley static int 37304e8ec74SJohn Daley mask_exact_match(const uint8_t *supported, const uint8_t *supplied, 374aa3d2ff8SJohn Daley unsigned int size) 375aa3d2ff8SJohn Daley { 376aa3d2ff8SJohn Daley unsigned int i; 377aa3d2ff8SJohn Daley for (i = 0; i < size; i++) { 378aa3d2ff8SJohn Daley if (supported[i] != supplied[i]) 379aa3d2ff8SJohn Daley return 0; 380aa3d2ff8SJohn Daley } 381aa3d2ff8SJohn Daley return 1; 382aa3d2ff8SJohn Daley } 383aa3d2ff8SJohn Daley 384aa3d2ff8SJohn Daley static int 38560c6acb4SHyong Youb Kim enic_copy_item_ipv4_v1(struct copy_item_args *arg) 386aa3d2ff8SJohn Daley { 38760c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 38860c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 389aa3d2ff8SJohn Daley const struct rte_flow_item_ipv4 *spec = item->spec; 390aa3d2ff8SJohn Daley const struct rte_flow_item_ipv4 *mask = item->mask; 391aa3d2ff8SJohn Daley struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; 392a7c528e5SOlivier Matz struct rte_ipv4_hdr supported_mask = { 393aa3d2ff8SJohn Daley .src_addr = 0xffffffff, 394aa3d2ff8SJohn Daley .dst_addr = 0xffffffff, 395aa3d2ff8SJohn Daley }; 396aa3d2ff8SJohn Daley 397bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 398aa3d2ff8SJohn Daley 399aa3d2ff8SJohn Daley if (!mask) 400aa3d2ff8SJohn Daley mask = &rte_flow_item_ipv4_mask; 401aa3d2ff8SJohn Daley 402aa3d2ff8SJohn Daley /* This is an exact match filter, both fields must be set */ 403aa3d2ff8SJohn Daley if (!spec || !spec->hdr.src_addr || !spec->hdr.dst_addr) { 404bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "IPv4 exact match src/dst addr"); 405aa3d2ff8SJohn Daley return ENOTSUP; 406aa3d2ff8SJohn Daley } 407aa3d2ff8SJohn Daley 4087be78d02SJosh Soref /* check that the supplied mask exactly matches capability */ 40904e8ec74SJohn Daley if (!mask_exact_match((const uint8_t *)&supported_mask, 41004e8ec74SJohn Daley (const uint8_t *)item->mask, sizeof(*mask))) { 411bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "IPv4 exact match mask"); 412aa3d2ff8SJohn Daley return ENOTSUP; 413aa3d2ff8SJohn Daley } 414aa3d2ff8SJohn Daley 415aa3d2ff8SJohn Daley enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; 416aa3d2ff8SJohn Daley enic_5tup->src_addr = spec->hdr.src_addr; 417aa3d2ff8SJohn Daley enic_5tup->dst_addr = spec->hdr.dst_addr; 418aa3d2ff8SJohn Daley 419aa3d2ff8SJohn Daley return 0; 420aa3d2ff8SJohn Daley } 421aa3d2ff8SJohn Daley 422aa3d2ff8SJohn Daley static int 42360c6acb4SHyong Youb Kim enic_copy_item_udp_v1(struct copy_item_args *arg) 424aa3d2ff8SJohn Daley { 42560c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 42660c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 427aa3d2ff8SJohn Daley const struct rte_flow_item_udp *spec = item->spec; 428aa3d2ff8SJohn Daley const struct rte_flow_item_udp *mask = item->mask; 429aa3d2ff8SJohn Daley struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; 430e73e3547SOlivier Matz struct rte_udp_hdr supported_mask = { 431aa3d2ff8SJohn Daley .src_port = 0xffff, 432aa3d2ff8SJohn Daley .dst_port = 0xffff, 433aa3d2ff8SJohn Daley }; 434aa3d2ff8SJohn Daley 435bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 436aa3d2ff8SJohn Daley 437aa3d2ff8SJohn Daley if (!mask) 438aa3d2ff8SJohn Daley mask = &rte_flow_item_udp_mask; 439aa3d2ff8SJohn Daley 440aa3d2ff8SJohn Daley /* This is an exact match filter, both ports must be set */ 441aa3d2ff8SJohn Daley if (!spec || !spec->hdr.src_port || !spec->hdr.dst_port) { 442bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "UDP exact match src/dst addr"); 443aa3d2ff8SJohn Daley return ENOTSUP; 444aa3d2ff8SJohn Daley } 445aa3d2ff8SJohn Daley 4467be78d02SJosh Soref /* check that the supplied mask exactly matches capability */ 44704e8ec74SJohn Daley if (!mask_exact_match((const uint8_t *)&supported_mask, 44804e8ec74SJohn Daley (const uint8_t *)item->mask, sizeof(*mask))) { 449bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "UDP exact match mask"); 450aa3d2ff8SJohn Daley return ENOTSUP; 451aa3d2ff8SJohn Daley } 452aa3d2ff8SJohn Daley 453aa3d2ff8SJohn Daley enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; 454aa3d2ff8SJohn Daley enic_5tup->src_port = spec->hdr.src_port; 455aa3d2ff8SJohn Daley enic_5tup->dst_port = spec->hdr.dst_port; 456aa3d2ff8SJohn Daley enic_5tup->protocol = PROTO_UDP; 457aa3d2ff8SJohn Daley 458aa3d2ff8SJohn Daley return 0; 459aa3d2ff8SJohn Daley } 460aa3d2ff8SJohn Daley 461aa3d2ff8SJohn Daley static int 46260c6acb4SHyong Youb Kim enic_copy_item_tcp_v1(struct copy_item_args *arg) 463aa3d2ff8SJohn Daley { 46460c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 46560c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 466aa3d2ff8SJohn Daley const struct rte_flow_item_tcp *spec = item->spec; 467aa3d2ff8SJohn Daley const struct rte_flow_item_tcp *mask = item->mask; 468aa3d2ff8SJohn Daley struct filter_ipv4_5tuple *enic_5tup = &enic_filter->u.ipv4; 469f41b5156SOlivier Matz struct rte_tcp_hdr supported_mask = { 470aa3d2ff8SJohn Daley .src_port = 0xffff, 471aa3d2ff8SJohn Daley .dst_port = 0xffff, 472aa3d2ff8SJohn Daley }; 473aa3d2ff8SJohn Daley 474bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 475aa3d2ff8SJohn Daley 476aa3d2ff8SJohn Daley if (!mask) 477aa3d2ff8SJohn Daley mask = &rte_flow_item_tcp_mask; 478aa3d2ff8SJohn Daley 479aa3d2ff8SJohn Daley /* This is an exact match filter, both ports must be set */ 480aa3d2ff8SJohn Daley if (!spec || !spec->hdr.src_port || !spec->hdr.dst_port) { 481bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "TCPIPv4 exact match src/dst addr"); 482aa3d2ff8SJohn Daley return ENOTSUP; 483aa3d2ff8SJohn Daley } 484aa3d2ff8SJohn Daley 4857be78d02SJosh Soref /* check that the supplied mask exactly matches capability */ 48604e8ec74SJohn Daley if (!mask_exact_match((const uint8_t *)&supported_mask, 48704e8ec74SJohn Daley (const uint8_t *)item->mask, sizeof(*mask))) { 488bbd8ecc0SJohn Daley ENICPMD_LOG(ERR, "TCP exact match mask"); 489aa3d2ff8SJohn Daley return ENOTSUP; 490aa3d2ff8SJohn Daley } 491aa3d2ff8SJohn Daley 492aa3d2ff8SJohn Daley enic_filter->u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE; 493aa3d2ff8SJohn Daley enic_5tup->src_port = spec->hdr.src_port; 494aa3d2ff8SJohn Daley enic_5tup->dst_port = spec->hdr.dst_port; 495aa3d2ff8SJohn Daley enic_5tup->protocol = PROTO_TCP; 496aa3d2ff8SJohn Daley 497aa3d2ff8SJohn Daley return 0; 498aa3d2ff8SJohn Daley } 499aa3d2ff8SJohn Daley 5004445a0f4SHyong Youb Kim /* 5014445a0f4SHyong Youb Kim * The common 'copy' function for all inner packet patterns. Patterns are 5024445a0f4SHyong Youb Kim * first appended to the L5 pattern buffer. Then, since the NIC filter 5034445a0f4SHyong Youb Kim * API has no special support for inner packet matching at the moment, 5044445a0f4SHyong Youb Kim * we set EtherType and IP proto as necessary. 5054445a0f4SHyong Youb Kim */ 5064445a0f4SHyong Youb Kim static int 5074445a0f4SHyong Youb Kim copy_inner_common(struct filter_generic_1 *gp, uint8_t *inner_ofst, 5084445a0f4SHyong Youb Kim const void *val, const void *mask, uint8_t val_size, 5094445a0f4SHyong Youb Kim uint8_t proto_off, uint16_t proto_val, uint8_t proto_size) 5104445a0f4SHyong Youb Kim { 5114445a0f4SHyong Youb Kim uint8_t *l5_mask, *l5_val; 5124445a0f4SHyong Youb Kim uint8_t start_off; 5134445a0f4SHyong Youb Kim 5144445a0f4SHyong Youb Kim /* No space left in the L5 pattern buffer. */ 5154445a0f4SHyong Youb Kim start_off = *inner_ofst; 5164445a0f4SHyong Youb Kim if ((start_off + val_size) > FILTER_GENERIC_1_KEY_LEN) 5174445a0f4SHyong Youb Kim return ENOTSUP; 5184445a0f4SHyong Youb Kim l5_mask = gp->layer[FILTER_GENERIC_1_L5].mask; 5194445a0f4SHyong Youb Kim l5_val = gp->layer[FILTER_GENERIC_1_L5].val; 5204445a0f4SHyong Youb Kim /* Copy the pattern into the L5 buffer. */ 5214445a0f4SHyong Youb Kim if (val) { 5224445a0f4SHyong Youb Kim memcpy(l5_mask + start_off, mask, val_size); 5234445a0f4SHyong Youb Kim memcpy(l5_val + start_off, val, val_size); 5244445a0f4SHyong Youb Kim } 5254445a0f4SHyong Youb Kim /* Set the protocol field in the previous header. */ 5264445a0f4SHyong Youb Kim if (proto_off) { 5274445a0f4SHyong Youb Kim void *m, *v; 5284445a0f4SHyong Youb Kim 5294445a0f4SHyong Youb Kim m = l5_mask + proto_off; 5304445a0f4SHyong Youb Kim v = l5_val + proto_off; 5314445a0f4SHyong Youb Kim if (proto_size == 1) { 5324445a0f4SHyong Youb Kim *(uint8_t *)m = 0xff; 5334445a0f4SHyong Youb Kim *(uint8_t *)v = (uint8_t)proto_val; 5344445a0f4SHyong Youb Kim } else if (proto_size == 2) { 5354445a0f4SHyong Youb Kim *(uint16_t *)m = 0xffff; 5364445a0f4SHyong Youb Kim *(uint16_t *)v = proto_val; 5374445a0f4SHyong Youb Kim } 5384445a0f4SHyong Youb Kim } 5394445a0f4SHyong Youb Kim /* All inner headers land in L5 buffer even if their spec is null. */ 5404445a0f4SHyong Youb Kim *inner_ofst += val_size; 5414445a0f4SHyong Youb Kim return 0; 5424445a0f4SHyong Youb Kim } 5434445a0f4SHyong Youb Kim 5444445a0f4SHyong Youb Kim static int 5454445a0f4SHyong Youb Kim enic_copy_item_inner_eth_v2(struct copy_item_args *arg) 5464445a0f4SHyong Youb Kim { 5474445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 5484445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 5494445a0f4SHyong Youb Kim 550bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 5514445a0f4SHyong Youb Kim if (!mask) 5524445a0f4SHyong Youb Kim mask = &rte_flow_item_eth_mask; 5536d13ea8eSOlivier Matz arg->l2_proto_off = *off + offsetof(struct rte_ether_hdr, ether_type); 5544445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 5556d13ea8eSOlivier Matz arg->item->spec, mask, sizeof(struct rte_ether_hdr), 5564445a0f4SHyong Youb Kim 0 /* no previous protocol */, 0, 0); 5574445a0f4SHyong Youb Kim } 5584445a0f4SHyong Youb Kim 5594445a0f4SHyong Youb Kim static int 5604445a0f4SHyong Youb Kim enic_copy_item_inner_vlan_v2(struct copy_item_args *arg) 5614445a0f4SHyong Youb Kim { 5624445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 5634445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 5644445a0f4SHyong Youb Kim uint8_t eth_type_off; 5654445a0f4SHyong Youb Kim 566bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 5674445a0f4SHyong Youb Kim if (!mask) 5684445a0f4SHyong Youb Kim mask = &rte_flow_item_vlan_mask; 5694445a0f4SHyong Youb Kim /* Append vlan header to L5 and set ether type = TPID */ 5704445a0f4SHyong Youb Kim eth_type_off = arg->l2_proto_off; 5716d13ea8eSOlivier Matz arg->l2_proto_off = *off + offsetof(struct rte_vlan_hdr, eth_proto); 5724445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 5736d13ea8eSOlivier Matz arg->item->spec, mask, sizeof(struct rte_vlan_hdr), 57435b2d13fSOlivier Matz eth_type_off, rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN), 2); 5754445a0f4SHyong Youb Kim } 5764445a0f4SHyong Youb Kim 5774445a0f4SHyong Youb Kim static int 5784445a0f4SHyong Youb Kim enic_copy_item_inner_ipv4_v2(struct copy_item_args *arg) 5794445a0f4SHyong Youb Kim { 5804445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 5814445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 5824445a0f4SHyong Youb Kim 583bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 5844445a0f4SHyong Youb Kim if (!mask) 5854445a0f4SHyong Youb Kim mask = &rte_flow_item_ipv4_mask; 5864445a0f4SHyong Youb Kim /* Append ipv4 header to L5 and set ether type = ipv4 */ 587a7c528e5SOlivier Matz arg->l3_proto_off = *off + offsetof(struct rte_ipv4_hdr, next_proto_id); 5884445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 589a7c528e5SOlivier Matz arg->item->spec, mask, sizeof(struct rte_ipv4_hdr), 5900c9da755SDavid Marchand arg->l2_proto_off, rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4), 2); 5914445a0f4SHyong Youb Kim } 5924445a0f4SHyong Youb Kim 5934445a0f4SHyong Youb Kim static int 5944445a0f4SHyong Youb Kim enic_copy_item_inner_ipv6_v2(struct copy_item_args *arg) 5954445a0f4SHyong Youb Kim { 5964445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 5974445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 5984445a0f4SHyong Youb Kim 599bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 6004445a0f4SHyong Youb Kim if (!mask) 6014445a0f4SHyong Youb Kim mask = &rte_flow_item_ipv6_mask; 6024445a0f4SHyong Youb Kim /* Append ipv6 header to L5 and set ether type = ipv6 */ 603a7c528e5SOlivier Matz arg->l3_proto_off = *off + offsetof(struct rte_ipv6_hdr, proto); 6044445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 605a7c528e5SOlivier Matz arg->item->spec, mask, sizeof(struct rte_ipv6_hdr), 6060c9da755SDavid Marchand arg->l2_proto_off, rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6), 2); 6074445a0f4SHyong Youb Kim } 6084445a0f4SHyong Youb Kim 6094445a0f4SHyong Youb Kim static int 6104445a0f4SHyong Youb Kim enic_copy_item_inner_udp_v2(struct copy_item_args *arg) 6114445a0f4SHyong Youb Kim { 6124445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 6134445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 6144445a0f4SHyong Youb Kim 615bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 6164445a0f4SHyong Youb Kim if (!mask) 6174445a0f4SHyong Youb Kim mask = &rte_flow_item_udp_mask; 6184445a0f4SHyong Youb Kim /* Append udp header to L5 and set ip proto = udp */ 6194445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 620e73e3547SOlivier Matz arg->item->spec, mask, sizeof(struct rte_udp_hdr), 6214445a0f4SHyong Youb Kim arg->l3_proto_off, IPPROTO_UDP, 1); 6224445a0f4SHyong Youb Kim } 6234445a0f4SHyong Youb Kim 6244445a0f4SHyong Youb Kim static int 6254445a0f4SHyong Youb Kim enic_copy_item_inner_tcp_v2(struct copy_item_args *arg) 6264445a0f4SHyong Youb Kim { 6274445a0f4SHyong Youb Kim const void *mask = arg->item->mask; 6284445a0f4SHyong Youb Kim uint8_t *off = arg->inner_ofst; 6294445a0f4SHyong Youb Kim 630bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 6314445a0f4SHyong Youb Kim if (!mask) 6324445a0f4SHyong Youb Kim mask = &rte_flow_item_tcp_mask; 6334445a0f4SHyong Youb Kim /* Append tcp header to L5 and set ip proto = tcp */ 6344445a0f4SHyong Youb Kim return copy_inner_common(&arg->filter->u.generic_1, off, 635f41b5156SOlivier Matz arg->item->spec, mask, sizeof(struct rte_tcp_hdr), 6364445a0f4SHyong Youb Kim arg->l3_proto_off, IPPROTO_TCP, 1); 6374445a0f4SHyong Youb Kim } 6384445a0f4SHyong Youb Kim 6396ced1376SJohn Daley static int 64060c6acb4SHyong Youb Kim enic_copy_item_eth_v2(struct copy_item_args *arg) 6416ced1376SJohn Daley { 64260c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 64360c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 6446d13ea8eSOlivier Matz struct rte_ether_hdr enic_spec; 6456d13ea8eSOlivier Matz struct rte_ether_hdr enic_mask; 6466ced1376SJohn Daley const struct rte_flow_item_eth *spec = item->spec; 6476ced1376SJohn Daley const struct rte_flow_item_eth *mask = item->mask; 6486ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 6496ced1376SJohn Daley 650bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 6516ced1376SJohn Daley 6526ced1376SJohn Daley /* Match all if no spec */ 6536ced1376SJohn Daley if (!spec) 6546ced1376SJohn Daley return 0; 6556ced1376SJohn Daley 6566ced1376SJohn Daley if (!mask) 6576ced1376SJohn Daley mask = &rte_flow_item_eth_mask; 6586ced1376SJohn Daley 6598275d5fcSThomas Monjalon memcpy(enic_spec.dst_addr.addr_bytes, spec->hdr.dst_addr.addr_bytes, 66035b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 6618275d5fcSThomas Monjalon memcpy(enic_spec.src_addr.addr_bytes, spec->hdr.src_addr.addr_bytes, 66235b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 6636ced1376SJohn Daley 6648275d5fcSThomas Monjalon memcpy(enic_mask.dst_addr.addr_bytes, mask->hdr.dst_addr.addr_bytes, 66535b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 6668275d5fcSThomas Monjalon memcpy(enic_mask.src_addr.addr_bytes, mask->hdr.src_addr.addr_bytes, 66735b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 6688275d5fcSThomas Monjalon enic_spec.ether_type = spec->hdr.ether_type; 6698275d5fcSThomas Monjalon enic_mask.ether_type = mask->hdr.ether_type; 6706ced1376SJohn Daley 6716ced1376SJohn Daley /* outer header */ 6726ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L2].mask, &enic_mask, 6736d13ea8eSOlivier Matz sizeof(struct rte_ether_hdr)); 6746ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L2].val, &enic_spec, 6756d13ea8eSOlivier Matz sizeof(struct rte_ether_hdr)); 6766ced1376SJohn Daley return 0; 6776ced1376SJohn Daley } 6786ced1376SJohn Daley 6796ced1376SJohn Daley static int 68060c6acb4SHyong Youb Kim enic_copy_item_vlan_v2(struct copy_item_args *arg) 6816ced1376SJohn Daley { 68260c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 68360c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 6846ced1376SJohn Daley const struct rte_flow_item_vlan *spec = item->spec; 6856ced1376SJohn Daley const struct rte_flow_item_vlan *mask = item->mask; 6866ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 6876d13ea8eSOlivier Matz struct rte_ether_hdr *eth_mask; 6886d13ea8eSOlivier Matz struct rte_ether_hdr *eth_val; 6896ced1376SJohn Daley 690bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 6916ced1376SJohn Daley 6926ced1376SJohn Daley /* Match all if no spec */ 6936ced1376SJohn Daley if (!spec) 6946ced1376SJohn Daley return 0; 6956ced1376SJohn Daley 696e58638c3SAdrien Mazarguil if (!mask) 6976ced1376SJohn Daley mask = &rte_flow_item_vlan_mask; 6986ced1376SJohn Daley 6994445a0f4SHyong Youb Kim eth_mask = (void *)gp->layer[FILTER_GENERIC_1_L2].mask; 7004445a0f4SHyong Youb Kim eth_val = (void *)gp->layer[FILTER_GENERIC_1_L2].val; 701e58638c3SAdrien Mazarguil /* Outer TPID cannot be matched */ 702e58638c3SAdrien Mazarguil if (eth_mask->ether_type) 703e58638c3SAdrien Mazarguil return ENOTSUP; 704593f1766SHyong Youb Kim /* 7056e54c8acSHyong Youb Kim * For recent models: 706593f1766SHyong Youb Kim * When packet matching, the VIC always compares vlan-stripped 707593f1766SHyong Youb Kim * L2, regardless of vlan stripping settings. So, the inner type 708593f1766SHyong Youb Kim * from vlan becomes the ether type of the eth header. 7096e54c8acSHyong Youb Kim * 7106e54c8acSHyong Youb Kim * Older models w/o hardware vxlan parser have a different 7116e54c8acSHyong Youb Kim * behavior when vlan stripping is disabled. In this case, 7126e54c8acSHyong Youb Kim * vlan tag remains in the L2 buffer. 713593f1766SHyong Youb Kim */ 7146e54c8acSHyong Youb Kim if (!arg->enic->vxlan && !arg->enic->ig_vlan_strip_en) { 7156d13ea8eSOlivier Matz struct rte_vlan_hdr *vlan; 7166e54c8acSHyong Youb Kim 7176d13ea8eSOlivier Matz vlan = (struct rte_vlan_hdr *)(eth_mask + 1); 7188275d5fcSThomas Monjalon vlan->eth_proto = mask->hdr.eth_proto; 7196d13ea8eSOlivier Matz vlan = (struct rte_vlan_hdr *)(eth_val + 1); 7208275d5fcSThomas Monjalon vlan->eth_proto = spec->hdr.eth_proto; 7216e54c8acSHyong Youb Kim } else { 7228275d5fcSThomas Monjalon eth_mask->ether_type = mask->hdr.eth_proto; 7238275d5fcSThomas Monjalon eth_val->ether_type = spec->hdr.eth_proto; 7246e54c8acSHyong Youb Kim } 725593f1766SHyong Youb Kim /* For TCI, use the vlan mask/val fields (little endian). */ 7268275d5fcSThomas Monjalon gp->mask_vlan = rte_be_to_cpu_16(mask->hdr.vlan_tci); 7278275d5fcSThomas Monjalon gp->val_vlan = rte_be_to_cpu_16(spec->hdr.vlan_tci); 7286ced1376SJohn Daley return 0; 7296ced1376SJohn Daley } 7306ced1376SJohn Daley 7316ced1376SJohn Daley static int 73260c6acb4SHyong Youb Kim enic_copy_item_ipv4_v2(struct copy_item_args *arg) 7336ced1376SJohn Daley { 73460c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 73560c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 7366ced1376SJohn Daley const struct rte_flow_item_ipv4 *spec = item->spec; 7376ced1376SJohn Daley const struct rte_flow_item_ipv4 *mask = item->mask; 7386ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 7396ced1376SJohn Daley 740bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 7416ced1376SJohn Daley 7426ced1376SJohn Daley /* Match IPv4 */ 7436ced1376SJohn Daley gp->mask_flags |= FILTER_GENERIC_1_IPV4; 7446ced1376SJohn Daley gp->val_flags |= FILTER_GENERIC_1_IPV4; 7456ced1376SJohn Daley 7466ced1376SJohn Daley /* Match all if no spec */ 7476ced1376SJohn Daley if (!spec) 7486ced1376SJohn Daley return 0; 7496ced1376SJohn Daley 7506ced1376SJohn Daley if (!mask) 7516ced1376SJohn Daley mask = &rte_flow_item_ipv4_mask; 7526ced1376SJohn Daley 7536ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L3].mask, &mask->hdr, 754a7c528e5SOlivier Matz sizeof(struct rte_ipv4_hdr)); 7556ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L3].val, &spec->hdr, 756a7c528e5SOlivier Matz sizeof(struct rte_ipv4_hdr)); 7576ced1376SJohn Daley return 0; 7586ced1376SJohn Daley } 7596ced1376SJohn Daley 7606ced1376SJohn Daley static int 76160c6acb4SHyong Youb Kim enic_copy_item_ipv6_v2(struct copy_item_args *arg) 7626ced1376SJohn Daley { 76360c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 76460c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 7656ced1376SJohn Daley const struct rte_flow_item_ipv6 *spec = item->spec; 7666ced1376SJohn Daley const struct rte_flow_item_ipv6 *mask = item->mask; 7676ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 7686ced1376SJohn Daley 769bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 7706ced1376SJohn Daley 7716ced1376SJohn Daley /* Match IPv6 */ 7726ced1376SJohn Daley gp->mask_flags |= FILTER_GENERIC_1_IPV6; 7736ced1376SJohn Daley gp->val_flags |= FILTER_GENERIC_1_IPV6; 7746ced1376SJohn Daley 7756ced1376SJohn Daley /* Match all if no spec */ 7766ced1376SJohn Daley if (!spec) 7776ced1376SJohn Daley return 0; 7786ced1376SJohn Daley 7796ced1376SJohn Daley if (!mask) 7806ced1376SJohn Daley mask = &rte_flow_item_ipv6_mask; 7816ced1376SJohn Daley 7826ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L3].mask, &mask->hdr, 783a7c528e5SOlivier Matz sizeof(struct rte_ipv6_hdr)); 7846ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L3].val, &spec->hdr, 785a7c528e5SOlivier Matz sizeof(struct rte_ipv6_hdr)); 7866ced1376SJohn Daley return 0; 7876ced1376SJohn Daley } 7886ced1376SJohn Daley 7896ced1376SJohn Daley static int 79060c6acb4SHyong Youb Kim enic_copy_item_udp_v2(struct copy_item_args *arg) 7916ced1376SJohn Daley { 79260c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 79360c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 7946ced1376SJohn Daley const struct rte_flow_item_udp *spec = item->spec; 7956ced1376SJohn Daley const struct rte_flow_item_udp *mask = item->mask; 7966ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 7976ced1376SJohn Daley 798bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 7996ced1376SJohn Daley 8006ced1376SJohn Daley /* Match UDP */ 8016ced1376SJohn Daley gp->mask_flags |= FILTER_GENERIC_1_UDP; 8026ced1376SJohn Daley gp->val_flags |= FILTER_GENERIC_1_UDP; 8036ced1376SJohn Daley 8046ced1376SJohn Daley /* Match all if no spec */ 8056ced1376SJohn Daley if (!spec) 8066ced1376SJohn Daley return 0; 8076ced1376SJohn Daley 8086ced1376SJohn Daley if (!mask) 8096ced1376SJohn Daley mask = &rte_flow_item_udp_mask; 8106ced1376SJohn Daley 8116ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].mask, &mask->hdr, 812e73e3547SOlivier Matz sizeof(struct rte_udp_hdr)); 8136ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].val, &spec->hdr, 814e73e3547SOlivier Matz sizeof(struct rte_udp_hdr)); 8156ced1376SJohn Daley return 0; 8166ced1376SJohn Daley } 8176ced1376SJohn Daley 8186ced1376SJohn Daley static int 81960c6acb4SHyong Youb Kim enic_copy_item_tcp_v2(struct copy_item_args *arg) 8206ced1376SJohn Daley { 82160c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 82260c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 8236ced1376SJohn Daley const struct rte_flow_item_tcp *spec = item->spec; 8246ced1376SJohn Daley const struct rte_flow_item_tcp *mask = item->mask; 8256ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 8266ced1376SJohn Daley 827bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 8286ced1376SJohn Daley 8296ced1376SJohn Daley /* Match TCP */ 8306ced1376SJohn Daley gp->mask_flags |= FILTER_GENERIC_1_TCP; 8316ced1376SJohn Daley gp->val_flags |= FILTER_GENERIC_1_TCP; 8326ced1376SJohn Daley 8336ced1376SJohn Daley /* Match all if no spec */ 8346ced1376SJohn Daley if (!spec) 8356ced1376SJohn Daley return 0; 8366ced1376SJohn Daley 8376ced1376SJohn Daley if (!mask) 8386ced1376SJohn Daley return ENOTSUP; 8396ced1376SJohn Daley 8406ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].mask, &mask->hdr, 841f41b5156SOlivier Matz sizeof(struct rte_tcp_hdr)); 8426ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].val, &spec->hdr, 843f41b5156SOlivier Matz sizeof(struct rte_tcp_hdr)); 8446ced1376SJohn Daley return 0; 8456ced1376SJohn Daley } 8466ced1376SJohn Daley 8476ced1376SJohn Daley static int 84860c6acb4SHyong Youb Kim enic_copy_item_sctp_v2(struct copy_item_args *arg) 8496ced1376SJohn Daley { 85060c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 85160c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 8526ced1376SJohn Daley const struct rte_flow_item_sctp *spec = item->spec; 8536ced1376SJohn Daley const struct rte_flow_item_sctp *mask = item->mask; 8546ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 8553a1c3cd0SHyong Youb Kim uint8_t *ip_proto_mask = NULL; 8563a1c3cd0SHyong Youb Kim uint8_t *ip_proto = NULL; 8576ced1376SJohn Daley 858bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 8596ced1376SJohn Daley 8603a1c3cd0SHyong Youb Kim /* 8613a1c3cd0SHyong Youb Kim * The NIC filter API has no flags for "match sctp", so explicitly set 8623a1c3cd0SHyong Youb Kim * the protocol number in the IP pattern. 8633a1c3cd0SHyong Youb Kim */ 8643a1c3cd0SHyong Youb Kim if (gp->val_flags & FILTER_GENERIC_1_IPV4) { 865a7c528e5SOlivier Matz struct rte_ipv4_hdr *ip; 866a7c528e5SOlivier Matz ip = (struct rte_ipv4_hdr *)gp->layer[FILTER_GENERIC_1_L3].mask; 8673a1c3cd0SHyong Youb Kim ip_proto_mask = &ip->next_proto_id; 868a7c528e5SOlivier Matz ip = (struct rte_ipv4_hdr *)gp->layer[FILTER_GENERIC_1_L3].val; 8693a1c3cd0SHyong Youb Kim ip_proto = &ip->next_proto_id; 8703a1c3cd0SHyong Youb Kim } else if (gp->val_flags & FILTER_GENERIC_1_IPV6) { 871a7c528e5SOlivier Matz struct rte_ipv6_hdr *ip; 872a7c528e5SOlivier Matz ip = (struct rte_ipv6_hdr *)gp->layer[FILTER_GENERIC_1_L3].mask; 8733a1c3cd0SHyong Youb Kim ip_proto_mask = &ip->proto; 874a7c528e5SOlivier Matz ip = (struct rte_ipv6_hdr *)gp->layer[FILTER_GENERIC_1_L3].val; 8753a1c3cd0SHyong Youb Kim ip_proto = &ip->proto; 8763a1c3cd0SHyong Youb Kim } else { 8773a1c3cd0SHyong Youb Kim /* Need IPv4/IPv6 pattern first */ 8783a1c3cd0SHyong Youb Kim return EINVAL; 8793a1c3cd0SHyong Youb Kim } 8803a1c3cd0SHyong Youb Kim *ip_proto = IPPROTO_SCTP; 8813a1c3cd0SHyong Youb Kim *ip_proto_mask = 0xff; 8823a1c3cd0SHyong Youb Kim 8836ced1376SJohn Daley /* Match all if no spec */ 8846ced1376SJohn Daley if (!spec) 8856ced1376SJohn Daley return 0; 8866ced1376SJohn Daley 8876ced1376SJohn Daley if (!mask) 8886ced1376SJohn Daley mask = &rte_flow_item_sctp_mask; 8896ced1376SJohn Daley 8906ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].mask, &mask->hdr, 89109d9ae1aSOlivier Matz sizeof(struct rte_sctp_hdr)); 8926ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L4].val, &spec->hdr, 89309d9ae1aSOlivier Matz sizeof(struct rte_sctp_hdr)); 8946ced1376SJohn Daley return 0; 8956ced1376SJohn Daley } 8966ced1376SJohn Daley 8976ced1376SJohn Daley static int 89860c6acb4SHyong Youb Kim enic_copy_item_vxlan_v2(struct copy_item_args *arg) 8996ced1376SJohn Daley { 90060c6acb4SHyong Youb Kim const struct rte_flow_item *item = arg->item; 90160c6acb4SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 90260c6acb4SHyong Youb Kim uint8_t *inner_ofst = arg->inner_ofst; 9036ced1376SJohn Daley const struct rte_flow_item_vxlan *spec = item->spec; 9046ced1376SJohn Daley const struct rte_flow_item_vxlan *mask = item->mask; 9056ced1376SJohn Daley struct filter_generic_1 *gp = &enic_filter->u.generic_1; 906e73e3547SOlivier Matz struct rte_udp_hdr *udp; 9076ced1376SJohn Daley 908bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 9096ced1376SJohn Daley 910d7316eaeSHyong Youb Kim /* 911d7316eaeSHyong Youb Kim * The NIC filter API has no flags for "match vxlan". Set UDP port to 912d7316eaeSHyong Youb Kim * avoid false positives. 913d7316eaeSHyong Youb Kim */ 914d7316eaeSHyong Youb Kim gp->mask_flags |= FILTER_GENERIC_1_UDP; 915d7316eaeSHyong Youb Kim gp->val_flags |= FILTER_GENERIC_1_UDP; 916e73e3547SOlivier Matz udp = (struct rte_udp_hdr *)gp->layer[FILTER_GENERIC_1_L4].mask; 917d7316eaeSHyong Youb Kim udp->dst_port = 0xffff; 918e73e3547SOlivier Matz udp = (struct rte_udp_hdr *)gp->layer[FILTER_GENERIC_1_L4].val; 919d7316eaeSHyong Youb Kim udp->dst_port = RTE_BE16(4789); 9206ced1376SJohn Daley /* Match all if no spec */ 9216ced1376SJohn Daley if (!spec) 9226ced1376SJohn Daley return 0; 9236ced1376SJohn Daley 9246ced1376SJohn Daley if (!mask) 9256ced1376SJohn Daley mask = &rte_flow_item_vxlan_mask; 9266ced1376SJohn Daley 9276ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L5].mask, mask, 9286d13ea8eSOlivier Matz sizeof(struct rte_vxlan_hdr)); 9296ced1376SJohn Daley memcpy(gp->layer[FILTER_GENERIC_1_L5].val, spec, 9306d13ea8eSOlivier Matz sizeof(struct rte_vxlan_hdr)); 9316ced1376SJohn Daley 9326d13ea8eSOlivier Matz *inner_ofst = sizeof(struct rte_vxlan_hdr); 9336ced1376SJohn Daley return 0; 9346ced1376SJohn Daley } 9356ced1376SJohn Daley 936477959e6SHyong Youb Kim /* 937477959e6SHyong Youb Kim * Copy raw item into version 2 NIC filter. Currently, raw pattern match is 938477959e6SHyong Youb Kim * very limited. It is intended for matching UDP tunnel header (e.g. vxlan 939477959e6SHyong Youb Kim * or geneve). 940477959e6SHyong Youb Kim */ 941477959e6SHyong Youb Kim static int 942477959e6SHyong Youb Kim enic_copy_item_raw_v2(struct copy_item_args *arg) 943477959e6SHyong Youb Kim { 944477959e6SHyong Youb Kim const struct rte_flow_item *item = arg->item; 945477959e6SHyong Youb Kim struct filter_v2 *enic_filter = arg->filter; 946477959e6SHyong Youb Kim uint8_t *inner_ofst = arg->inner_ofst; 947477959e6SHyong Youb Kim const struct rte_flow_item_raw *spec = item->spec; 948477959e6SHyong Youb Kim const struct rte_flow_item_raw *mask = item->mask; 949477959e6SHyong Youb Kim struct filter_generic_1 *gp = &enic_filter->u.generic_1; 950477959e6SHyong Youb Kim 951bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 952477959e6SHyong Youb Kim 953477959e6SHyong Youb Kim /* Cannot be used for inner packet */ 954477959e6SHyong Youb Kim if (*inner_ofst) 955477959e6SHyong Youb Kim return EINVAL; 956477959e6SHyong Youb Kim /* Need both spec and mask */ 957477959e6SHyong Youb Kim if (!spec || !mask) 958477959e6SHyong Youb Kim return EINVAL; 959477959e6SHyong Youb Kim /* Only supports relative with offset 0 */ 960477959e6SHyong Youb Kim if (!spec->relative || spec->offset != 0 || spec->search || spec->limit) 961477959e6SHyong Youb Kim return EINVAL; 962477959e6SHyong Youb Kim /* Need non-null pattern that fits within the NIC's filter pattern */ 96337b07be2SHyong Youb Kim if (spec->length == 0 || 964e73e3547SOlivier Matz spec->length + sizeof(struct rte_udp_hdr) > FILTER_GENERIC_1_KEY_LEN || 965477959e6SHyong Youb Kim !spec->pattern || !mask->pattern) 966477959e6SHyong Youb Kim return EINVAL; 967477959e6SHyong Youb Kim /* 968477959e6SHyong Youb Kim * Mask fields, including length, are often set to zero. Assume that 969477959e6SHyong Youb Kim * means "same as spec" to avoid breaking existing apps. If length 970477959e6SHyong Youb Kim * is not zero, then it should be >= spec length. 971477959e6SHyong Youb Kim * 972477959e6SHyong Youb Kim * No more pattern follows this, so append to the L4 layer instead of 973477959e6SHyong Youb Kim * L5 to work with both recent and older VICs. 974477959e6SHyong Youb Kim */ 975477959e6SHyong Youb Kim if (mask->length != 0 && mask->length < spec->length) 976477959e6SHyong Youb Kim return EINVAL; 977e73e3547SOlivier Matz memcpy(gp->layer[FILTER_GENERIC_1_L4].mask + sizeof(struct rte_udp_hdr), 978477959e6SHyong Youb Kim mask->pattern, spec->length); 979e73e3547SOlivier Matz memcpy(gp->layer[FILTER_GENERIC_1_L4].val + sizeof(struct rte_udp_hdr), 980477959e6SHyong Youb Kim spec->pattern, spec->length); 981477959e6SHyong Youb Kim 982477959e6SHyong Youb Kim return 0; 983477959e6SHyong Youb Kim } 984477959e6SHyong Youb Kim 9856ced1376SJohn Daley /** 9866ced1376SJohn Daley * Return 1 if current item is valid on top of the previous one. 9876ced1376SJohn Daley * 9886ced1376SJohn Daley * @param prev_item[in] 9896ced1376SJohn Daley * The item before this one in the pattern or RTE_FLOW_ITEM_TYPE_END if this 9906ced1376SJohn Daley * is the first item. 9916ced1376SJohn Daley * @param item_info[in] 9926ced1376SJohn Daley * Info about this item, like valid previous items. 9936ced1376SJohn Daley * @param is_first[in] 9946ced1376SJohn Daley * True if this the first item in the pattern. 9956ced1376SJohn Daley */ 9966ced1376SJohn Daley static int 9976ced1376SJohn Daley item_stacking_valid(enum rte_flow_item_type prev_item, 99804e8ec74SJohn Daley const struct enic_items *item_info, uint8_t is_first_item) 9996ced1376SJohn Daley { 10006ced1376SJohn Daley enum rte_flow_item_type const *allowed_items = item_info->prev_items; 10016ced1376SJohn Daley 1002bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 10036ced1376SJohn Daley 10046ced1376SJohn Daley for (; *allowed_items != RTE_FLOW_ITEM_TYPE_END; allowed_items++) { 10056ced1376SJohn Daley if (prev_item == *allowed_items) 10066ced1376SJohn Daley return 1; 10076ced1376SJohn Daley } 10086ced1376SJohn Daley 10096ced1376SJohn Daley /* This is the first item in the stack. Check if that's cool */ 10106ced1376SJohn Daley if (is_first_item && item_info->valid_start_item) 10116ced1376SJohn Daley return 1; 10126ced1376SJohn Daley 10136ced1376SJohn Daley return 0; 10146ced1376SJohn Daley } 10156ced1376SJohn Daley 1016d7316eaeSHyong Youb Kim /* 1017d7316eaeSHyong Youb Kim * Fix up the L5 layer.. HW vxlan parsing removes vxlan header from L5. 1018d7316eaeSHyong Youb Kim * Instead it is in L4 following the UDP header. Append the vxlan 1019d7316eaeSHyong Youb Kim * pattern to L4 (udp) and shift any inner packet pattern in L5. 1020d7316eaeSHyong Youb Kim */ 1021d7316eaeSHyong Youb Kim static void 1022d7316eaeSHyong Youb Kim fixup_l5_layer(struct enic *enic, struct filter_generic_1 *gp, 1023d7316eaeSHyong Youb Kim uint8_t inner_ofst) 1024d7316eaeSHyong Youb Kim { 1025d7316eaeSHyong Youb Kim uint8_t layer[FILTER_GENERIC_1_KEY_LEN]; 1026d7316eaeSHyong Youb Kim uint8_t inner; 1027d7316eaeSHyong Youb Kim uint8_t vxlan; 1028d7316eaeSHyong Youb Kim 1029d7316eaeSHyong Youb Kim if (!(inner_ofst > 0 && enic->vxlan)) 1030d7316eaeSHyong Youb Kim return; 1031bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 10326d13ea8eSOlivier Matz vxlan = sizeof(struct rte_vxlan_hdr); 1033e73e3547SOlivier Matz memcpy(gp->layer[FILTER_GENERIC_1_L4].mask + sizeof(struct rte_udp_hdr), 1034d7316eaeSHyong Youb Kim gp->layer[FILTER_GENERIC_1_L5].mask, vxlan); 1035e73e3547SOlivier Matz memcpy(gp->layer[FILTER_GENERIC_1_L4].val + sizeof(struct rte_udp_hdr), 1036d7316eaeSHyong Youb Kim gp->layer[FILTER_GENERIC_1_L5].val, vxlan); 1037d7316eaeSHyong Youb Kim inner = inner_ofst - vxlan; 1038d7316eaeSHyong Youb Kim memset(layer, 0, sizeof(layer)); 1039d7316eaeSHyong Youb Kim memcpy(layer, gp->layer[FILTER_GENERIC_1_L5].mask + vxlan, inner); 1040d7316eaeSHyong Youb Kim memcpy(gp->layer[FILTER_GENERIC_1_L5].mask, layer, sizeof(layer)); 1041d7316eaeSHyong Youb Kim memset(layer, 0, sizeof(layer)); 1042d7316eaeSHyong Youb Kim memcpy(layer, gp->layer[FILTER_GENERIC_1_L5].val + vxlan, inner); 1043d7316eaeSHyong Youb Kim memcpy(gp->layer[FILTER_GENERIC_1_L5].val, layer, sizeof(layer)); 1044d7316eaeSHyong Youb Kim } 1045d7316eaeSHyong Youb Kim 10466ced1376SJohn Daley /** 10477be78d02SJosh Soref * Build the internal enic filter structure from the provided pattern. The 10486ced1376SJohn Daley * pattern is validated as the items are copied. 10496ced1376SJohn Daley * 10506ced1376SJohn Daley * @param pattern[in] 10516ced1376SJohn Daley * @param items_info[in] 10526ced1376SJohn Daley * Info about this NICs item support, like valid previous items. 10536ced1376SJohn Daley * @param enic_filter[out] 10547be78d02SJosh Soref * NIC specific filters derived from the pattern. 10556ced1376SJohn Daley * @param error[out] 10566ced1376SJohn Daley */ 10576ced1376SJohn Daley static int 10586ced1376SJohn Daley enic_copy_filter(const struct rte_flow_item pattern[], 10594d8e9aa4SHyong Youb Kim const struct enic_filter_cap *cap, 1060d7316eaeSHyong Youb Kim struct enic *enic, 10616ced1376SJohn Daley struct filter_v2 *enic_filter, 10626ced1376SJohn Daley struct rte_flow_error *error) 10636ced1376SJohn Daley { 10646ced1376SJohn Daley int ret; 10656ced1376SJohn Daley const struct rte_flow_item *item = pattern; 106604e8ec74SJohn Daley uint8_t inner_ofst = 0; /* If encapsulated, ofst into L5 */ 10676ced1376SJohn Daley enum rte_flow_item_type prev_item; 10686ced1376SJohn Daley const struct enic_items *item_info; 106960c6acb4SHyong Youb Kim struct copy_item_args args; 10704445a0f4SHyong Youb Kim enic_copy_item_fn *copy_fn; 107104e8ec74SJohn Daley uint8_t is_first_item = 1; 10726ced1376SJohn Daley 1073bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 10746ced1376SJohn Daley 10756ced1376SJohn Daley prev_item = 0; 10766ced1376SJohn Daley 107760c6acb4SHyong Youb Kim args.filter = enic_filter; 107860c6acb4SHyong Youb Kim args.inner_ofst = &inner_ofst; 10796e54c8acSHyong Youb Kim args.enic = enic; 10806ced1376SJohn Daley for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { 10816ced1376SJohn Daley /* Get info about how to validate and copy the item. If NULL 10826ced1376SJohn Daley * is returned the nic does not support the item. 10836ced1376SJohn Daley */ 10846ced1376SJohn Daley if (item->type == RTE_FLOW_ITEM_TYPE_VOID) 10856ced1376SJohn Daley continue; 10866ced1376SJohn Daley 10874d8e9aa4SHyong Youb Kim item_info = &cap->item_info[item->type]; 10884d8e9aa4SHyong Youb Kim if (item->type > cap->max_item_type || 10894445a0f4SHyong Youb Kim item_info->copy_item == NULL || 10904445a0f4SHyong Youb Kim (inner_ofst > 0 && item_info->inner_copy_item == NULL)) { 10914d8e9aa4SHyong Youb Kim rte_flow_error_set(error, ENOTSUP, 10924d8e9aa4SHyong Youb Kim RTE_FLOW_ERROR_TYPE_ITEM, 10934d8e9aa4SHyong Youb Kim NULL, "Unsupported item."); 10944d8e9aa4SHyong Youb Kim return -rte_errno; 10954d8e9aa4SHyong Youb Kim } 10966ced1376SJohn Daley 10976ced1376SJohn Daley /* check to see if item stacking is valid */ 10986ced1376SJohn Daley if (!item_stacking_valid(prev_item, item_info, is_first_item)) 10996ced1376SJohn Daley goto stacking_error; 11006ced1376SJohn Daley 110160c6acb4SHyong Youb Kim args.item = item; 11024445a0f4SHyong Youb Kim copy_fn = inner_ofst > 0 ? item_info->inner_copy_item : 11034445a0f4SHyong Youb Kim item_info->copy_item; 11044445a0f4SHyong Youb Kim ret = copy_fn(&args); 11056ced1376SJohn Daley if (ret) 11066ced1376SJohn Daley goto item_not_supported; 11076ced1376SJohn Daley prev_item = item->type; 11086ced1376SJohn Daley is_first_item = 0; 11096ced1376SJohn Daley } 1110d7316eaeSHyong Youb Kim fixup_l5_layer(enic, &enic_filter->u.generic_1, inner_ofst); 1111d7316eaeSHyong Youb Kim 11126ced1376SJohn Daley return 0; 11136ced1376SJohn Daley 11146ced1376SJohn Daley item_not_supported: 11156ced1376SJohn Daley rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_ITEM, 11166ced1376SJohn Daley NULL, "enic type error"); 11176ced1376SJohn Daley return -rte_errno; 11186ced1376SJohn Daley 11196ced1376SJohn Daley stacking_error: 11206ced1376SJohn Daley rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, 11216ced1376SJohn Daley item, "stacking error"); 11226ced1376SJohn Daley return -rte_errno; 11236ced1376SJohn Daley } 112426faa126SJohn Daley 112526faa126SJohn Daley /** 11267be78d02SJosh Soref * Build the internal version 1 NIC action structure from the provided pattern. 112726faa126SJohn Daley * The pattern is validated as the items are copied. 112826faa126SJohn Daley * 112926faa126SJohn Daley * @param actions[in] 113026faa126SJohn Daley * @param enic_action[out] 11317be78d02SJosh Soref * NIC specific actions derived from the actions. 113226faa126SJohn Daley * @param error[out] 113326faa126SJohn Daley */ 113426faa126SJohn Daley static int 1135e9434f6fSHyong Youb Kim enic_copy_action_v1(__rte_unused struct enic *enic, 1136e9434f6fSHyong Youb Kim const struct rte_flow_action actions[], 113726faa126SJohn Daley struct filter_action_v2 *enic_action) 113826faa126SJohn Daley { 1139cc17feb9SAdrien Mazarguil enum { FATE = 1, }; 1140cc17feb9SAdrien Mazarguil uint32_t overlap = 0; 1141cc17feb9SAdrien Mazarguil 1142bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 114326faa126SJohn Daley 114426faa126SJohn Daley for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 114526faa126SJohn Daley if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) 114626faa126SJohn Daley continue; 114726faa126SJohn Daley 114826faa126SJohn Daley switch (actions->type) { 114926faa126SJohn Daley case RTE_FLOW_ACTION_TYPE_QUEUE: { 115026faa126SJohn Daley const struct rte_flow_action_queue *queue = 115126faa126SJohn Daley (const struct rte_flow_action_queue *) 115226faa126SJohn Daley actions->conf; 1153cc17feb9SAdrien Mazarguil 1154cc17feb9SAdrien Mazarguil if (overlap & FATE) 1155cc17feb9SAdrien Mazarguil return ENOTSUP; 1156cc17feb9SAdrien Mazarguil overlap |= FATE; 115726faa126SJohn Daley enic_action->rq_idx = 115826faa126SJohn Daley enic_rte_rq_idx_to_sop_idx(queue->index); 115926faa126SJohn Daley break; 116026faa126SJohn Daley } 116126faa126SJohn Daley default: 116226faa126SJohn Daley RTE_ASSERT(0); 116326faa126SJohn Daley break; 116426faa126SJohn Daley } 116526faa126SJohn Daley } 1166cc17feb9SAdrien Mazarguil if (!(overlap & FATE)) 1167cc17feb9SAdrien Mazarguil return ENOTSUP; 116826faa126SJohn Daley enic_action->type = FILTER_ACTION_RQ_STEERING; 116926faa126SJohn Daley return 0; 117026faa126SJohn Daley } 117126faa126SJohn Daley 11726ced1376SJohn Daley /** 11737be78d02SJosh Soref * Build the internal version 2 NIC action structure from the provided pattern. 11746ced1376SJohn Daley * The pattern is validated as the items are copied. 11756ced1376SJohn Daley * 11766ced1376SJohn Daley * @param actions[in] 11776ced1376SJohn Daley * @param enic_action[out] 11787be78d02SJosh Soref * NIC specific actions derived from the actions. 11796ced1376SJohn Daley * @param error[out] 11806ced1376SJohn Daley */ 11816ced1376SJohn Daley static int 1182e9434f6fSHyong Youb Kim enic_copy_action_v2(struct enic *enic, 1183e9434f6fSHyong Youb Kim const struct rte_flow_action actions[], 11846ced1376SJohn Daley struct filter_action_v2 *enic_action) 11856ced1376SJohn Daley { 1186cc17feb9SAdrien Mazarguil enum { FATE = 1, MARK = 2, }; 1187cc17feb9SAdrien Mazarguil uint32_t overlap = 0; 11885af7af4dSHyong Youb Kim bool passthru = false; 1189cc17feb9SAdrien Mazarguil 1190bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 11916ced1376SJohn Daley 11926ced1376SJohn Daley for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 11936ced1376SJohn Daley switch (actions->type) { 11946ced1376SJohn Daley case RTE_FLOW_ACTION_TYPE_QUEUE: { 11956ced1376SJohn Daley const struct rte_flow_action_queue *queue = 11966ced1376SJohn Daley (const struct rte_flow_action_queue *) 11976ced1376SJohn Daley actions->conf; 1198cc17feb9SAdrien Mazarguil 1199cc17feb9SAdrien Mazarguil if (overlap & FATE) 1200cc17feb9SAdrien Mazarguil return ENOTSUP; 1201cc17feb9SAdrien Mazarguil overlap |= FATE; 12026ced1376SJohn Daley enic_action->rq_idx = 12036ced1376SJohn Daley enic_rte_rq_idx_to_sop_idx(queue->index); 12046ced1376SJohn Daley enic_action->flags |= FILTER_ACTION_RQ_STEERING_FLAG; 12056ced1376SJohn Daley break; 12066ced1376SJohn Daley } 12076ced1376SJohn Daley case RTE_FLOW_ACTION_TYPE_MARK: { 12086ced1376SJohn Daley const struct rte_flow_action_mark *mark = 12096ced1376SJohn Daley (const struct rte_flow_action_mark *) 12106ced1376SJohn Daley actions->conf; 12118ffaae0dSJohn Daley if (enic->use_noscatter_vec_rx_handler) 12128ffaae0dSJohn Daley return ENOTSUP; 1213cc17feb9SAdrien Mazarguil if (overlap & MARK) 1214cc17feb9SAdrien Mazarguil return ENOTSUP; 1215cc17feb9SAdrien Mazarguil overlap |= MARK; 1216e7347a8aSHyong Youb Kim /* 1217e7347a8aSHyong Youb Kim * Map mark ID (32-bit) to filter ID (16-bit): 1218e7347a8aSHyong Youb Kim * - Reject values > 16 bits 1219e7347a8aSHyong Youb Kim * - Filter ID 0 is reserved for filters that steer 1220e7347a8aSHyong Youb Kim * but not mark. So add 1 to the mark ID to avoid 1221e7347a8aSHyong Youb Kim * using 0. 1222e7347a8aSHyong Youb Kim * - Filter ID (ENIC_MAGIC_FILTER_ID = 0xffff) is 1223e7347a8aSHyong Youb Kim * reserved for the "flag" action below. 12246ced1376SJohn Daley */ 1225e7347a8aSHyong Youb Kim if (mark->id >= ENIC_MAGIC_FILTER_ID - 1) 12266ced1376SJohn Daley return EINVAL; 1227e7347a8aSHyong Youb Kim enic_action->filter_id = mark->id + 1; 12286ced1376SJohn Daley enic_action->flags |= FILTER_ACTION_FILTER_ID_FLAG; 12296ced1376SJohn Daley break; 12306ced1376SJohn Daley } 12316ced1376SJohn Daley case RTE_FLOW_ACTION_TYPE_FLAG: { 12328ffaae0dSJohn Daley if (enic->use_noscatter_vec_rx_handler) 12338ffaae0dSJohn Daley return ENOTSUP; 1234cc17feb9SAdrien Mazarguil if (overlap & MARK) 1235cc17feb9SAdrien Mazarguil return ENOTSUP; 1236cc17feb9SAdrien Mazarguil overlap |= MARK; 1237e7347a8aSHyong Youb Kim /* ENIC_MAGIC_FILTER_ID is reserved for flagging */ 12386ced1376SJohn Daley enic_action->filter_id = ENIC_MAGIC_FILTER_ID; 12396ced1376SJohn Daley enic_action->flags |= FILTER_ACTION_FILTER_ID_FLAG; 12406ced1376SJohn Daley break; 12416ced1376SJohn Daley } 1242036c545dSHyong Youb Kim case RTE_FLOW_ACTION_TYPE_DROP: { 12439713ece2SHyong Youb Kim if (overlap & FATE) 12449713ece2SHyong Youb Kim return ENOTSUP; 12459713ece2SHyong Youb Kim overlap |= FATE; 1246036c545dSHyong Youb Kim enic_action->flags |= FILTER_ACTION_DROP_FLAG; 1247036c545dSHyong Youb Kim break; 1248036c545dSHyong Youb Kim } 1249e9434f6fSHyong Youb Kim case RTE_FLOW_ACTION_TYPE_RSS: { 1250e9434f6fSHyong Youb Kim const struct rte_flow_action_rss *rss = 1251e9434f6fSHyong Youb Kim (const struct rte_flow_action_rss *) 1252e9434f6fSHyong Youb Kim actions->conf; 1253e9434f6fSHyong Youb Kim bool allow; 1254e9434f6fSHyong Youb Kim uint16_t i; 1255e9434f6fSHyong Youb Kim 1256e9434f6fSHyong Youb Kim /* 1257e9434f6fSHyong Youb Kim * Hardware does not support general RSS actions, but 1258e9434f6fSHyong Youb Kim * we can still support the dummy one that is used to 1259e9434f6fSHyong Youb Kim * "receive normally". 1260e9434f6fSHyong Youb Kim */ 1261e9434f6fSHyong Youb Kim allow = rss->func == RTE_ETH_HASH_FUNCTION_DEFAULT && 1262e9434f6fSHyong Youb Kim rss->level == 0 && 1263e9434f6fSHyong Youb Kim (rss->types == 0 || 1264e9434f6fSHyong Youb Kim rss->types == enic->rss_hf) && 1265e9434f6fSHyong Youb Kim rss->queue_num == enic->rq_count && 1266e9434f6fSHyong Youb Kim rss->key_len == 0; 1267e9434f6fSHyong Youb Kim /* Identity queue map is ok */ 1268e9434f6fSHyong Youb Kim for (i = 0; i < rss->queue_num; i++) 1269e9434f6fSHyong Youb Kim allow = allow && (i == rss->queue[i]); 1270e9434f6fSHyong Youb Kim if (!allow) 1271e9434f6fSHyong Youb Kim return ENOTSUP; 1272e9434f6fSHyong Youb Kim if (overlap & FATE) 1273e9434f6fSHyong Youb Kim return ENOTSUP; 1274e9434f6fSHyong Youb Kim /* Need MARK or FLAG */ 1275e9434f6fSHyong Youb Kim if (!(overlap & MARK)) 1276e9434f6fSHyong Youb Kim return ENOTSUP; 1277e9434f6fSHyong Youb Kim overlap |= FATE; 1278e9434f6fSHyong Youb Kim break; 1279e9434f6fSHyong Youb Kim } 12805af7af4dSHyong Youb Kim case RTE_FLOW_ACTION_TYPE_PASSTHRU: { 12815af7af4dSHyong Youb Kim /* 12825af7af4dSHyong Youb Kim * Like RSS above, PASSTHRU + MARK may be used to 12835af7af4dSHyong Youb Kim * "mark and then receive normally". MARK usually comes 12845af7af4dSHyong Youb Kim * after PASSTHRU, so remember we have seen passthru 12855af7af4dSHyong Youb Kim * and check for mark later. 12865af7af4dSHyong Youb Kim */ 12875af7af4dSHyong Youb Kim if (overlap & FATE) 12885af7af4dSHyong Youb Kim return ENOTSUP; 12895af7af4dSHyong Youb Kim overlap |= FATE; 12905af7af4dSHyong Youb Kim passthru = true; 12915af7af4dSHyong Youb Kim break; 12925af7af4dSHyong Youb Kim } 12936ced1376SJohn Daley case RTE_FLOW_ACTION_TYPE_VOID: 12946ced1376SJohn Daley continue; 12956ced1376SJohn Daley default: 12966ced1376SJohn Daley RTE_ASSERT(0); 12976ced1376SJohn Daley break; 12986ced1376SJohn Daley } 12996ced1376SJohn Daley } 13005af7af4dSHyong Youb Kim /* Only PASSTHRU + MARK is allowed */ 13015af7af4dSHyong Youb Kim if (passthru && !(overlap & MARK)) 13025af7af4dSHyong Youb Kim return ENOTSUP; 1303cc17feb9SAdrien Mazarguil if (!(overlap & FATE)) 1304cc17feb9SAdrien Mazarguil return ENOTSUP; 13056ced1376SJohn Daley enic_action->type = FILTER_ACTION_V2; 13066ced1376SJohn Daley return 0; 13076ced1376SJohn Daley } 13086ced1376SJohn Daley 13096ced1376SJohn Daley /** Check if the action is supported */ 13106ced1376SJohn Daley static int 13116ced1376SJohn Daley enic_match_action(const struct rte_flow_action *action, 13126ced1376SJohn Daley const enum rte_flow_action_type *supported_actions) 13136ced1376SJohn Daley { 13146ced1376SJohn Daley for (; *supported_actions != RTE_FLOW_ACTION_TYPE_END; 13156ced1376SJohn Daley supported_actions++) { 13166ced1376SJohn Daley if (action->type == *supported_actions) 13176ced1376SJohn Daley return 1; 13186ced1376SJohn Daley } 13196ced1376SJohn Daley return 0; 13206ced1376SJohn Daley } 13216ced1376SJohn Daley 13226ced1376SJohn Daley /** Get the NIC filter capabilties structure */ 13236ced1376SJohn Daley static const struct enic_filter_cap * 13246ced1376SJohn Daley enic_get_filter_cap(struct enic *enic) 13256ced1376SJohn Daley { 13266ced1376SJohn Daley if (enic->flow_filter_mode) 13276ced1376SJohn Daley return &enic_filter_cap[enic->flow_filter_mode]; 13286ced1376SJohn Daley 13296ced1376SJohn Daley return NULL; 13306ced1376SJohn Daley } 13316ced1376SJohn Daley 13326ced1376SJohn Daley /** Get the actions for this NIC version. */ 13336ced1376SJohn Daley static const struct enic_action_cap * 13346ced1376SJohn Daley enic_get_action_cap(struct enic *enic) 13356ced1376SJohn Daley { 1336036c545dSHyong Youb Kim const struct enic_action_cap *ea; 1337036c545dSHyong Youb Kim uint8_t actions; 13386ced1376SJohn Daley 1339036c545dSHyong Youb Kim actions = enic->filter_actions; 1340d74111a9SJohn Daley if (actions & FILTER_ACTION_DROP_FLAG) 1341036c545dSHyong Youb Kim ea = &enic_action_cap[FILTER_ACTION_DROP_FLAG]; 1342036c545dSHyong Youb Kim else if (actions & FILTER_ACTION_FILTER_ID_FLAG) 1343036c545dSHyong Youb Kim ea = &enic_action_cap[FILTER_ACTION_FILTER_ID_FLAG]; 134426faa126SJohn Daley else 134526faa126SJohn Daley ea = &enic_action_cap[FILTER_ACTION_RQ_STEERING_FLAG]; 13466ced1376SJohn Daley return ea; 13476ced1376SJohn Daley } 1348936a9b99SJohn Daley 1349936a9b99SJohn Daley /* Debug function to dump internal NIC action structure. */ 1350936a9b99SJohn Daley static void 1351936a9b99SJohn Daley enic_dump_actions(const struct filter_action_v2 *ea) 1352936a9b99SJohn Daley { 1353936a9b99SJohn Daley if (ea->type == FILTER_ACTION_RQ_STEERING) { 1354*f665790aSDavid Marchand ENICPMD_LOG(INFO, "Action(V1), queue: %u", ea->rq_idx); 1355936a9b99SJohn Daley } else if (ea->type == FILTER_ACTION_V2) { 1356*f665790aSDavid Marchand ENICPMD_LOG(INFO, "Actions(V2)"); 1357936a9b99SJohn Daley if (ea->flags & FILTER_ACTION_RQ_STEERING_FLAG) 1358*f665790aSDavid Marchand ENICPMD_LOG(INFO, "\tqueue: %u", 1359936a9b99SJohn Daley enic_sop_rq_idx_to_rte_idx(ea->rq_idx)); 1360936a9b99SJohn Daley if (ea->flags & FILTER_ACTION_FILTER_ID_FLAG) 1361*f665790aSDavid Marchand ENICPMD_LOG(INFO, "\tfilter_id: %u", ea->filter_id); 1362936a9b99SJohn Daley } 1363936a9b99SJohn Daley } 1364936a9b99SJohn Daley 1365936a9b99SJohn Daley /* Debug function to dump internal NIC filter structure. */ 1366936a9b99SJohn Daley static void 1367936a9b99SJohn Daley enic_dump_filter(const struct filter_v2 *filt) 1368936a9b99SJohn Daley { 1369936a9b99SJohn Daley const struct filter_generic_1 *gp; 1370936a9b99SJohn Daley int i, j, mbyte; 1371936a9b99SJohn Daley char buf[128], *bp; 1372936a9b99SJohn Daley char ip4[16], ip6[16], udp[16], tcp[16], tcpudp[16], ip4csum[16]; 1373936a9b99SJohn Daley char l4csum[16], ipfrag[16]; 1374936a9b99SJohn Daley 1375936a9b99SJohn Daley switch (filt->type) { 1376936a9b99SJohn Daley case FILTER_IPV4_5TUPLE: 1377*f665790aSDavid Marchand ENICPMD_LOG(INFO, "FILTER_IPV4_5TUPLE"); 1378936a9b99SJohn Daley break; 1379936a9b99SJohn Daley case FILTER_USNIC_IP: 1380936a9b99SJohn Daley case FILTER_DPDK_1: 1381936a9b99SJohn Daley /* FIXME: this should be a loop */ 1382936a9b99SJohn Daley gp = &filt->u.generic_1; 1383*f665790aSDavid Marchand ENICPMD_LOG(INFO, "Filter: vlan: 0x%04x, mask: 0x%04x", 1384936a9b99SJohn Daley gp->val_vlan, gp->mask_vlan); 1385936a9b99SJohn Daley 1386936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_IPV4) 1387936a9b99SJohn Daley sprintf(ip4, "%s ", 1388936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_IPV4) 1389936a9b99SJohn Daley ? "ip4(y)" : "ip4(n)"); 1390936a9b99SJohn Daley else 1391936a9b99SJohn Daley sprintf(ip4, "%s ", "ip4(x)"); 1392936a9b99SJohn Daley 1393936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_IPV6) 1394936a9b99SJohn Daley sprintf(ip6, "%s ", 139589ce72c6SHyong Youb Kim (gp->val_flags & FILTER_GENERIC_1_IPV6) 1396936a9b99SJohn Daley ? "ip6(y)" : "ip6(n)"); 1397936a9b99SJohn Daley else 1398936a9b99SJohn Daley sprintf(ip6, "%s ", "ip6(x)"); 1399936a9b99SJohn Daley 1400936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_UDP) 1401936a9b99SJohn Daley sprintf(udp, "%s ", 1402936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_UDP) 1403936a9b99SJohn Daley ? "udp(y)" : "udp(n)"); 1404936a9b99SJohn Daley else 1405936a9b99SJohn Daley sprintf(udp, "%s ", "udp(x)"); 1406936a9b99SJohn Daley 1407936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_TCP) 1408936a9b99SJohn Daley sprintf(tcp, "%s ", 1409936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_TCP) 1410936a9b99SJohn Daley ? "tcp(y)" : "tcp(n)"); 1411936a9b99SJohn Daley else 1412936a9b99SJohn Daley sprintf(tcp, "%s ", "tcp(x)"); 1413936a9b99SJohn Daley 1414936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_TCP_OR_UDP) 1415936a9b99SJohn Daley sprintf(tcpudp, "%s ", 1416936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_TCP_OR_UDP) 1417936a9b99SJohn Daley ? "tcpudp(y)" : "tcpudp(n)"); 1418936a9b99SJohn Daley else 1419936a9b99SJohn Daley sprintf(tcpudp, "%s ", "tcpudp(x)"); 1420936a9b99SJohn Daley 1421936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_IP4SUM_OK) 1422936a9b99SJohn Daley sprintf(ip4csum, "%s ", 1423936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_IP4SUM_OK) 1424936a9b99SJohn Daley ? "ip4csum(y)" : "ip4csum(n)"); 1425936a9b99SJohn Daley else 1426936a9b99SJohn Daley sprintf(ip4csum, "%s ", "ip4csum(x)"); 1427936a9b99SJohn Daley 1428936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_L4SUM_OK) 1429936a9b99SJohn Daley sprintf(l4csum, "%s ", 1430936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_L4SUM_OK) 1431936a9b99SJohn Daley ? "l4csum(y)" : "l4csum(n)"); 1432936a9b99SJohn Daley else 1433936a9b99SJohn Daley sprintf(l4csum, "%s ", "l4csum(x)"); 1434936a9b99SJohn Daley 1435936a9b99SJohn Daley if (gp->mask_flags & FILTER_GENERIC_1_IPFRAG) 1436936a9b99SJohn Daley sprintf(ipfrag, "%s ", 1437936a9b99SJohn Daley (gp->val_flags & FILTER_GENERIC_1_IPFRAG) 1438936a9b99SJohn Daley ? "ipfrag(y)" : "ipfrag(n)"); 1439936a9b99SJohn Daley else 1440936a9b99SJohn Daley sprintf(ipfrag, "%s ", "ipfrag(x)"); 1441*f665790aSDavid Marchand ENICPMD_LOG(INFO, "\tFlags: %s%s%s%s%s%s%s%s", ip4, ip6, udp, 1442936a9b99SJohn Daley tcp, tcpudp, ip4csum, l4csum, ipfrag); 1443936a9b99SJohn Daley 1444936a9b99SJohn Daley for (i = 0; i < FILTER_GENERIC_1_NUM_LAYERS; i++) { 1445936a9b99SJohn Daley mbyte = FILTER_GENERIC_1_KEY_LEN - 1; 1446936a9b99SJohn Daley while (mbyte && !gp->layer[i].mask[mbyte]) 1447936a9b99SJohn Daley mbyte--; 1448936a9b99SJohn Daley if (mbyte == 0) 1449936a9b99SJohn Daley continue; 1450936a9b99SJohn Daley 1451936a9b99SJohn Daley bp = buf; 1452936a9b99SJohn Daley for (j = 0; j <= mbyte; j++) { 1453936a9b99SJohn Daley sprintf(bp, "%02x", 1454936a9b99SJohn Daley gp->layer[i].mask[j]); 1455936a9b99SJohn Daley bp += 2; 1456936a9b99SJohn Daley } 1457936a9b99SJohn Daley *bp = '\0'; 1458*f665790aSDavid Marchand ENICPMD_LOG(INFO, "\tL%u mask: %s", i + 2, buf); 1459936a9b99SJohn Daley bp = buf; 1460936a9b99SJohn Daley for (j = 0; j <= mbyte; j++) { 1461936a9b99SJohn Daley sprintf(bp, "%02x", 1462936a9b99SJohn Daley gp->layer[i].val[j]); 1463936a9b99SJohn Daley bp += 2; 1464936a9b99SJohn Daley } 1465936a9b99SJohn Daley *bp = '\0'; 1466*f665790aSDavid Marchand ENICPMD_LOG(INFO, "\tL%u val: %s", i + 2, buf); 1467936a9b99SJohn Daley } 1468936a9b99SJohn Daley break; 1469936a9b99SJohn Daley default: 1470*f665790aSDavid Marchand ENICPMD_LOG(INFO, "FILTER UNKNOWN"); 1471936a9b99SJohn Daley break; 1472936a9b99SJohn Daley } 1473936a9b99SJohn Daley } 1474936a9b99SJohn Daley 1475936a9b99SJohn Daley /* Debug function to dump internal NIC flow structures. */ 1476936a9b99SJohn Daley static void 1477936a9b99SJohn Daley enic_dump_flow(const struct filter_action_v2 *ea, const struct filter_v2 *filt) 1478936a9b99SJohn Daley { 1479936a9b99SJohn Daley enic_dump_filter(filt); 1480936a9b99SJohn Daley enic_dump_actions(ea); 1481936a9b99SJohn Daley } 1482936a9b99SJohn Daley 1483936a9b99SJohn Daley 14846ced1376SJohn Daley /** 14856ced1376SJohn Daley * Internal flow parse/validate function. 14866ced1376SJohn Daley * 14876ced1376SJohn Daley * @param dev[in] 14886ced1376SJohn Daley * This device pointer. 14896ced1376SJohn Daley * @param pattern[in] 14906ced1376SJohn Daley * @param actions[in] 14916ced1376SJohn Daley * @param error[out] 14926ced1376SJohn Daley * @param enic_filter[out] 14936ced1376SJohn Daley * Internal NIC filter structure pointer. 14946ced1376SJohn Daley * @param enic_action[out] 14956ced1376SJohn Daley * Internal NIC action structure pointer. 14966ced1376SJohn Daley */ 14976ced1376SJohn Daley static int 14986ced1376SJohn Daley enic_flow_parse(struct rte_eth_dev *dev, 14996ced1376SJohn Daley const struct rte_flow_attr *attrs, 15006ced1376SJohn Daley const struct rte_flow_item pattern[], 15016ced1376SJohn Daley const struct rte_flow_action actions[], 15026ced1376SJohn Daley struct rte_flow_error *error, 15036ced1376SJohn Daley struct filter_v2 *enic_filter, 15046ced1376SJohn Daley struct filter_action_v2 *enic_action) 15056ced1376SJohn Daley { 15066ced1376SJohn Daley unsigned int ret = 0; 15076ced1376SJohn Daley struct enic *enic = pmd_priv(dev); 15086ced1376SJohn Daley const struct enic_filter_cap *enic_filter_cap; 15096ced1376SJohn Daley const struct enic_action_cap *enic_action_cap; 15106ced1376SJohn Daley const struct rte_flow_action *action; 15116ced1376SJohn Daley 1512bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 15136ced1376SJohn Daley 15146ced1376SJohn Daley memset(enic_filter, 0, sizeof(*enic_filter)); 15156ced1376SJohn Daley memset(enic_action, 0, sizeof(*enic_action)); 15166ced1376SJohn Daley 15176ced1376SJohn Daley if (!pattern) { 15186ced1376SJohn Daley rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM, 15196ced1376SJohn Daley NULL, "No pattern specified"); 15206ced1376SJohn Daley return -rte_errno; 15216ced1376SJohn Daley } 15226ced1376SJohn Daley 15236ced1376SJohn Daley if (!actions) { 15246ced1376SJohn Daley rte_flow_error_set(error, EINVAL, 15256ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ACTION_NUM, 15266ced1376SJohn Daley NULL, "No action specified"); 15276ced1376SJohn Daley return -rte_errno; 15286ced1376SJohn Daley } 15296ced1376SJohn Daley 15306ced1376SJohn Daley if (attrs) { 15316ced1376SJohn Daley if (attrs->group) { 15326ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, 15336ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 15346ced1376SJohn Daley NULL, 15356ced1376SJohn Daley "priority groups are not supported"); 15366ced1376SJohn Daley return -rte_errno; 15376ced1376SJohn Daley } else if (attrs->priority) { 15386ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, 15396ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, 15406ced1376SJohn Daley NULL, 15416ced1376SJohn Daley "priorities are not supported"); 15426ced1376SJohn Daley return -rte_errno; 15436ced1376SJohn Daley } else if (attrs->egress) { 15446ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, 15456ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, 15466ced1376SJohn Daley NULL, 15476ced1376SJohn Daley "egress is not supported"); 15486ced1376SJohn Daley return -rte_errno; 154976e9a55bSAdrien Mazarguil } else if (attrs->transfer) { 155076e9a55bSAdrien Mazarguil rte_flow_error_set(error, ENOTSUP, 155176e9a55bSAdrien Mazarguil RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, 155276e9a55bSAdrien Mazarguil NULL, 155376e9a55bSAdrien Mazarguil "transfer is not supported"); 155476e9a55bSAdrien Mazarguil return -rte_errno; 15556ced1376SJohn Daley } else if (!attrs->ingress) { 15566ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, 15576ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, 15586ced1376SJohn Daley NULL, 15596ced1376SJohn Daley "only ingress is supported"); 15606ced1376SJohn Daley return -rte_errno; 15616ced1376SJohn Daley } 15626ced1376SJohn Daley 15636ced1376SJohn Daley } else { 15646ced1376SJohn Daley rte_flow_error_set(error, EINVAL, 15656ced1376SJohn Daley RTE_FLOW_ERROR_TYPE_ATTR, 15666ced1376SJohn Daley NULL, "No attribute specified"); 15676ced1376SJohn Daley return -rte_errno; 15686ced1376SJohn Daley } 15696ced1376SJohn Daley 15706ced1376SJohn Daley /* Verify Actions. */ 15716ced1376SJohn Daley enic_action_cap = enic_get_action_cap(enic); 15726ced1376SJohn Daley for (action = &actions[0]; action->type != RTE_FLOW_ACTION_TYPE_END; 15736ced1376SJohn Daley action++) { 15746ced1376SJohn Daley if (action->type == RTE_FLOW_ACTION_TYPE_VOID) 15756ced1376SJohn Daley continue; 15766ced1376SJohn Daley else if (!enic_match_action(action, enic_action_cap->actions)) 15776ced1376SJohn Daley break; 15786ced1376SJohn Daley } 15796ced1376SJohn Daley if (action->type != RTE_FLOW_ACTION_TYPE_END) { 15806ced1376SJohn Daley rte_flow_error_set(error, EPERM, RTE_FLOW_ERROR_TYPE_ACTION, 15816ced1376SJohn Daley action, "Invalid action."); 15826ced1376SJohn Daley return -rte_errno; 15836ced1376SJohn Daley } 1584e9434f6fSHyong Youb Kim ret = enic_action_cap->copy_fn(enic, actions, enic_action); 15856ced1376SJohn Daley if (ret) { 15866ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, 15876ced1376SJohn Daley NULL, "Unsupported action."); 15886ced1376SJohn Daley return -rte_errno; 15896ced1376SJohn Daley } 15906ced1376SJohn Daley 15916ced1376SJohn Daley /* Verify Flow items. If copying the filter from flow format to enic 15926ced1376SJohn Daley * format fails, the flow is not supported 15936ced1376SJohn Daley */ 15946ced1376SJohn Daley enic_filter_cap = enic_get_filter_cap(enic); 15956ced1376SJohn Daley if (enic_filter_cap == NULL) { 15966ced1376SJohn Daley rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, 15976ced1376SJohn Daley NULL, "Flow API not available"); 15986ced1376SJohn Daley return -rte_errno; 15996ced1376SJohn Daley } 160026faa126SJohn Daley enic_filter->type = enic->flow_filter_mode; 1601d700f0d0SHyong Youb Kim if (enic->adv_filters) 1602d700f0d0SHyong Youb Kim enic_filter->type = FILTER_DPDK_1; 1603d7316eaeSHyong Youb Kim ret = enic_copy_filter(pattern, enic_filter_cap, enic, 16046ced1376SJohn Daley enic_filter, error); 16056ced1376SJohn Daley return ret; 16066ced1376SJohn Daley } 16076ced1376SJohn Daley 16086ced1376SJohn Daley /** 16096ced1376SJohn Daley * Push filter/action to the NIC. 16106ced1376SJohn Daley * 16116ced1376SJohn Daley * @param enic[in] 16126ced1376SJohn Daley * Device structure pointer. 16136ced1376SJohn Daley * @param enic_filter[in] 16146ced1376SJohn Daley * Internal NIC filter structure pointer. 16156ced1376SJohn Daley * @param enic_action[in] 16166ced1376SJohn Daley * Internal NIC action structure pointer. 16176ced1376SJohn Daley * @param error[out] 16186ced1376SJohn Daley */ 16196ced1376SJohn Daley static struct rte_flow * 16206ced1376SJohn Daley enic_flow_add_filter(struct enic *enic, struct filter_v2 *enic_filter, 16216ced1376SJohn Daley struct filter_action_v2 *enic_action, 16226ced1376SJohn Daley struct rte_flow_error *error) 16236ced1376SJohn Daley { 16246ced1376SJohn Daley struct rte_flow *flow; 162586df6c4eSJohn Daley int err; 162604e8ec74SJohn Daley uint16_t entry; 16276ced1376SJohn Daley 1628bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 16296ced1376SJohn Daley 16306ced1376SJohn Daley flow = rte_calloc(__func__, 1, sizeof(*flow), 0); 16316ced1376SJohn Daley if (!flow) { 16326ced1376SJohn Daley rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, 16336ced1376SJohn Daley NULL, "cannot allocate flow memory"); 16346ced1376SJohn Daley return NULL; 16356ced1376SJohn Daley } 16366ced1376SJohn Daley 16376ced1376SJohn Daley /* entry[in] is the queue id, entry[out] is the filter Id for delete */ 16386ced1376SJohn Daley entry = enic_action->rq_idx; 163986df6c4eSJohn Daley err = vnic_dev_classifier(enic->vdev, CLSF_ADD, &entry, enic_filter, 16406ced1376SJohn Daley enic_action); 164186df6c4eSJohn Daley if (err) { 164286df6c4eSJohn Daley rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, 164386df6c4eSJohn Daley NULL, "vnic_dev_classifier error"); 1644d74111a9SJohn Daley rte_free(flow); 1645d74111a9SJohn Daley return NULL; 164686df6c4eSJohn Daley } 164786df6c4eSJohn Daley 16486ced1376SJohn Daley flow->enic_filter_id = entry; 16496ced1376SJohn Daley flow->enic_filter = *enic_filter; 165086df6c4eSJohn Daley return flow; 16516ced1376SJohn Daley } 16526ced1376SJohn Daley 16536ced1376SJohn Daley /** 16546ced1376SJohn Daley * Remove filter/action from the NIC. 16556ced1376SJohn Daley * 16566ced1376SJohn Daley * @param enic[in] 16576ced1376SJohn Daley * Device structure pointer. 16586ced1376SJohn Daley * @param filter_id[in] 16596ced1376SJohn Daley * Id of NIC filter. 16606ced1376SJohn Daley * @param enic_action[in] 16616ced1376SJohn Daley * Internal NIC action structure pointer. 16626ced1376SJohn Daley * @param error[out] 16636ced1376SJohn Daley */ 16646ced1376SJohn Daley static int 166586df6c4eSJohn Daley enic_flow_del_filter(struct enic *enic, struct rte_flow *flow, 16666ced1376SJohn Daley struct rte_flow_error *error) 16676ced1376SJohn Daley { 166804e8ec74SJohn Daley uint16_t filter_id; 166986df6c4eSJohn Daley int err; 16706ced1376SJohn Daley 1671bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 16726ced1376SJohn Daley 167386df6c4eSJohn Daley filter_id = flow->enic_filter_id; 167486df6c4eSJohn Daley err = vnic_dev_classifier(enic->vdev, CLSF_DEL, &filter_id, NULL, NULL); 167586df6c4eSJohn Daley if (err) { 167686df6c4eSJohn Daley rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, 16776ced1376SJohn Daley NULL, "vnic_dev_classifier failed"); 167886df6c4eSJohn Daley return -err; 167986df6c4eSJohn Daley } 168086df6c4eSJohn Daley return 0; 16816ced1376SJohn Daley } 16826ced1376SJohn Daley 16830f766680SJohn Daley /* 16840f766680SJohn Daley * The following functions are callbacks for Generic flow API. 16850f766680SJohn Daley */ 16860f766680SJohn Daley 16870f766680SJohn Daley /** 16880f766680SJohn Daley * Validate a flow supported by the NIC. 16890f766680SJohn Daley * 16900f766680SJohn Daley * @see rte_flow_validate() 16910f766680SJohn Daley * @see rte_flow_ops 16920f766680SJohn Daley */ 16930f766680SJohn Daley static int 16940f766680SJohn Daley enic_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attrs, 16950f766680SJohn Daley const struct rte_flow_item pattern[], 16960f766680SJohn Daley const struct rte_flow_action actions[], 16970f766680SJohn Daley struct rte_flow_error *error) 16980f766680SJohn Daley { 16996ced1376SJohn Daley struct filter_v2 enic_filter; 17006ced1376SJohn Daley struct filter_action_v2 enic_action; 17016ced1376SJohn Daley int ret; 17020f766680SJohn Daley 1703bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 17040f766680SJohn Daley 17056ced1376SJohn Daley ret = enic_flow_parse(dev, attrs, pattern, actions, error, 17066ced1376SJohn Daley &enic_filter, &enic_action); 1707936a9b99SJohn Daley if (!ret) 1708936a9b99SJohn Daley enic_dump_flow(&enic_action, &enic_filter); 17096ced1376SJohn Daley return ret; 17100f766680SJohn Daley } 17110f766680SJohn Daley 17120f766680SJohn Daley /** 17130f766680SJohn Daley * Create a flow supported by the NIC. 17140f766680SJohn Daley * 17150f766680SJohn Daley * @see rte_flow_create() 17160f766680SJohn Daley * @see rte_flow_ops 17170f766680SJohn Daley */ 17180f766680SJohn Daley static struct rte_flow * 17190f766680SJohn Daley enic_flow_create(struct rte_eth_dev *dev, 17200f766680SJohn Daley const struct rte_flow_attr *attrs, 17210f766680SJohn Daley const struct rte_flow_item pattern[], 17220f766680SJohn Daley const struct rte_flow_action actions[], 17230f766680SJohn Daley struct rte_flow_error *error) 17240f766680SJohn Daley { 17256ced1376SJohn Daley int ret; 17266ced1376SJohn Daley struct filter_v2 enic_filter; 17276ced1376SJohn Daley struct filter_action_v2 enic_action; 17286ced1376SJohn Daley struct rte_flow *flow; 17296ced1376SJohn Daley struct enic *enic = pmd_priv(dev); 17300f766680SJohn Daley 1731bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 17320f766680SJohn Daley 17336ced1376SJohn Daley ret = enic_flow_parse(dev, attrs, pattern, actions, error, &enic_filter, 17346ced1376SJohn Daley &enic_action); 17356ced1376SJohn Daley if (ret < 0) 17360f766680SJohn Daley return NULL; 17376ced1376SJohn Daley 17386ced1376SJohn Daley flow = enic_flow_add_filter(enic, &enic_filter, &enic_action, 17396ced1376SJohn Daley error); 17406ced1376SJohn Daley if (flow) 17416ced1376SJohn Daley LIST_INSERT_HEAD(&enic->flows, flow, next); 17426ced1376SJohn Daley 17436ced1376SJohn Daley return flow; 17440f766680SJohn Daley } 17450f766680SJohn Daley 17460f766680SJohn Daley /** 17470f766680SJohn Daley * Destroy a flow supported by the NIC. 17480f766680SJohn Daley * 17490f766680SJohn Daley * @see rte_flow_destroy() 17500f766680SJohn Daley * @see rte_flow_ops 17510f766680SJohn Daley */ 17520f766680SJohn Daley static int 17530f766680SJohn Daley enic_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow, 17540f766680SJohn Daley __rte_unused struct rte_flow_error *error) 17550f766680SJohn Daley { 17566ced1376SJohn Daley struct enic *enic = pmd_priv(dev); 17570f766680SJohn Daley 1758bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 17590f766680SJohn Daley 176086df6c4eSJohn Daley enic_flow_del_filter(enic, flow, error); 17616ced1376SJohn Daley LIST_REMOVE(flow, next); 176285b0ccecSJohn Daley rte_free(flow); 17630f766680SJohn Daley return 0; 17640f766680SJohn Daley } 17650f766680SJohn Daley 17660f766680SJohn Daley /** 17670f766680SJohn Daley * Flush all flows on the device. 17680f766680SJohn Daley * 17690f766680SJohn Daley * @see rte_flow_flush() 17700f766680SJohn Daley * @see rte_flow_ops 17710f766680SJohn Daley */ 17720f766680SJohn Daley static int 17730f766680SJohn Daley enic_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error) 17740f766680SJohn Daley { 17756ced1376SJohn Daley struct rte_flow *flow; 17766ced1376SJohn Daley struct enic *enic = pmd_priv(dev); 17770f766680SJohn Daley 1778bbd8ecc0SJohn Daley ENICPMD_FUNC_TRACE(); 17790f766680SJohn Daley 17806ced1376SJohn Daley 17816ced1376SJohn Daley while (!LIST_EMPTY(&enic->flows)) { 17826ced1376SJohn Daley flow = LIST_FIRST(&enic->flows); 178386df6c4eSJohn Daley enic_flow_del_filter(enic, flow, error); 17846ced1376SJohn Daley LIST_REMOVE(flow, next); 178585b0ccecSJohn Daley rte_free(flow); 17866ced1376SJohn Daley } 17870f766680SJohn Daley return 0; 17880f766680SJohn Daley } 17890f766680SJohn Daley 17900f766680SJohn Daley /** 17910f766680SJohn Daley * Flow callback registration. 17920f766680SJohn Daley * 17930f766680SJohn Daley * @see rte_flow_ops 17940f766680SJohn Daley */ 17950f766680SJohn Daley const struct rte_flow_ops enic_flow_ops = { 17960f766680SJohn Daley .validate = enic_flow_validate, 17970f766680SJohn Daley .create = enic_flow_create, 17980f766680SJohn Daley .destroy = enic_flow_destroy, 17990f766680SJohn Daley .flush = enic_flow_flush, 18000f766680SJohn Daley }; 1801