1a551c94aSIdo Barnea/*-
2a551c94aSIdo Barnea *   BSD LICENSE
3a551c94aSIdo Barnea *
4a551c94aSIdo Barnea *   Copyright 2015 6WIND S.A.
5a551c94aSIdo Barnea *   Copyright 2015 Mellanox.
6a551c94aSIdo Barnea *
7a551c94aSIdo Barnea *   Redistribution and use in source and binary forms, with or without
8a551c94aSIdo Barnea *   modification, are permitted provided that the following conditions
9a551c94aSIdo Barnea *   are met:
10a551c94aSIdo Barnea *
11a551c94aSIdo Barnea *     * Redistributions of source code must retain the above copyright
12a551c94aSIdo Barnea *       notice, this list of conditions and the following disclaimer.
13a551c94aSIdo Barnea *     * Redistributions in binary form must reproduce the above copyright
14a551c94aSIdo Barnea *       notice, this list of conditions and the following disclaimer in
15a551c94aSIdo Barnea *       the documentation and/or other materials provided with the
16a551c94aSIdo Barnea *       distribution.
17a551c94aSIdo Barnea *     * Neither the name of 6WIND S.A. nor the names of its
18a551c94aSIdo Barnea *       contributors may be used to endorse or promote products derived
19a551c94aSIdo Barnea *       from this software without specific prior written permission.
20a551c94aSIdo Barnea *
21a551c94aSIdo Barnea *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22a551c94aSIdo Barnea *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23a551c94aSIdo Barnea *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24a551c94aSIdo Barnea *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25a551c94aSIdo Barnea *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26a551c94aSIdo Barnea *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27a551c94aSIdo Barnea *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28a551c94aSIdo Barnea *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29a551c94aSIdo Barnea *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30a551c94aSIdo Barnea *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31a551c94aSIdo Barnea *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32a551c94aSIdo Barnea */
33a551c94aSIdo Barnea
34a551c94aSIdo Barnea#include <stddef.h>
35a551c94aSIdo Barnea#include <assert.h>
36a551c94aSIdo Barnea#include <stdint.h>
37a551c94aSIdo Barnea#include <string.h>
38a551c94aSIdo Barnea#include <errno.h>
39a551c94aSIdo Barnea
4066937478SHanoh Haim#define TREX_PATCH
4166937478SHanoh Haim
42a551c94aSIdo Barnea/* Verbs header. */
43a551c94aSIdo Barnea/* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
44a551c94aSIdo Barnea#ifdef PEDANTIC
45be13fd96SHanoh Haim#pragma GCC diagnostic ignored "-Wpedantic"
46a551c94aSIdo Barnea#endif
4766937478SHanoh Haim#include <infiniband/verbs_exp.h>
48a551c94aSIdo Barnea#ifdef PEDANTIC
49be13fd96SHanoh Haim#pragma GCC diagnostic error "-Wpedantic"
50a551c94aSIdo Barnea#endif
51a551c94aSIdo Barnea
52a551c94aSIdo Barnea/* DPDK headers don't like -pedantic. */
53a551c94aSIdo Barnea#ifdef PEDANTIC
54be13fd96SHanoh Haim#pragma GCC diagnostic ignored "-Wpedantic"
55a551c94aSIdo Barnea#endif
56a551c94aSIdo Barnea#include <rte_ether.h>
57a551c94aSIdo Barnea#include <rte_malloc.h>
58a551c94aSIdo Barnea#include <rte_ethdev.h>
59a551c94aSIdo Barnea#include <rte_common.h>
609ca4a157SIdo Barnea#include <rte_flow.h>
619ca4a157SIdo Barnea#include <rte_flow_driver.h>
62a551c94aSIdo Barnea#ifdef PEDANTIC
63be13fd96SHanoh Haim#pragma GCC diagnostic error "-Wpedantic"
64a551c94aSIdo Barnea#endif
65a551c94aSIdo Barnea
66a551c94aSIdo Barnea#include "mlx5.h"
67a551c94aSIdo Barnea#include "mlx5_rxtx.h"
68a551c94aSIdo Barnea
69a551c94aSIdo Barneastruct fdir_flow_desc {
70a551c94aSIdo Barnea	uint16_t dst_port;
71a551c94aSIdo Barnea	uint16_t src_port;
72a551c94aSIdo Barnea	uint32_t src_ip[4];
73a551c94aSIdo Barnea	uint32_t dst_ip[4];
7466937478SHanoh Haim    uint8_t  tos;
7566937478SHanoh Haim    uint8_t  ip_id;
7666937478SHanoh Haim    uint8_t  proto;
77a551c94aSIdo Barnea	uint8_t	mac[6];
78a551c94aSIdo Barnea	uint16_t vlan_tag;
79a551c94aSIdo Barnea	enum hash_rxq_type type;
80a551c94aSIdo Barnea};
81a551c94aSIdo Barnea
82a551c94aSIdo Barneastruct mlx5_fdir_filter {
83a551c94aSIdo Barnea	LIST_ENTRY(mlx5_fdir_filter) next;
84a551c94aSIdo Barnea	uint16_t queue; /* Queue assigned to if FDIR match. */
85be13fd96SHanoh Haim	enum rte_eth_fdir_behavior behavior;
86a551c94aSIdo Barnea	struct fdir_flow_desc desc;
87a551c94aSIdo Barnea	struct ibv_exp_flow *flow;
88a551c94aSIdo Barnea};
89a551c94aSIdo Barnea
90a551c94aSIdo BarneaLIST_HEAD(fdir_filter_list, mlx5_fdir_filter);
91a551c94aSIdo Barnea
92a551c94aSIdo Barnea/**
93a551c94aSIdo Barnea * Convert struct rte_eth_fdir_filter to mlx5 filter descriptor.
94a551c94aSIdo Barnea *
95a551c94aSIdo Barnea * @param[in] fdir_filter
96a551c94aSIdo Barnea *   DPDK filter structure to convert.
97a551c94aSIdo Barnea * @param[out] desc
98a551c94aSIdo Barnea *   Resulting mlx5 filter descriptor.
99a551c94aSIdo Barnea * @param mode
100a551c94aSIdo Barnea *   Flow director mode.
101a551c94aSIdo Barnea */
102a551c94aSIdo Barneastatic void
103a551c94aSIdo Barneafdir_filter_to_flow_desc(const struct rte_eth_fdir_filter *fdir_filter,
104a551c94aSIdo Barnea			 struct fdir_flow_desc *desc, enum rte_fdir_mode mode)
105a551c94aSIdo Barnea{
106a551c94aSIdo Barnea	/* Initialize descriptor. */
107a551c94aSIdo Barnea	memset(desc, 0, sizeof(*desc));
108a551c94aSIdo Barnea
109a551c94aSIdo Barnea	/* Set VLAN ID. */
110a551c94aSIdo Barnea	desc->vlan_tag = fdir_filter->input.flow_ext.vlan_tci;
111a551c94aSIdo Barnea
11266937478SHanoh Haim#ifndef TREX_PATCH
113a551c94aSIdo Barnea	/* Set MAC address. */
114a551c94aSIdo Barnea	if (mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
115a551c94aSIdo Barnea		rte_memcpy(desc->mac,
116a551c94aSIdo Barnea			   fdir_filter->input.flow.mac_vlan_flow.mac_addr.
117a551c94aSIdo Barnea				addr_bytes,
118a551c94aSIdo Barnea			   sizeof(desc->mac));
119a551c94aSIdo Barnea		desc->type = HASH_RXQ_ETH;
120a551c94aSIdo Barnea		return;
121a551c94aSIdo Barnea	}
12266937478SHanoh Haim#else
12366937478SHanoh Haim    if (fdir_filter->input.flow.ip4_flow.ip_id == 2) {
12466937478SHanoh Haim        desc->type = HASH_RXQ_ETH;
12566937478SHanoh Haim        desc->ip_id = fdir_filter->input.flow.ip4_flow.ip_id;
12666937478SHanoh Haim        return;
12766937478SHanoh Haim    }
12866937478SHanoh Haim#endif
12966937478SHanoh Haim
130a551c94aSIdo Barnea
131a551c94aSIdo Barnea	/* Set mode */
132a551c94aSIdo Barnea	switch (fdir_filter->input.flow_type) {
133a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
134a551c94aSIdo Barnea		desc->type = HASH_RXQ_UDPV4;
135a551c94aSIdo Barnea		break;
136a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
137a551c94aSIdo Barnea		desc->type = HASH_RXQ_TCPV4;
138a551c94aSIdo Barnea		break;
139a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
140a551c94aSIdo Barnea		desc->type = HASH_RXQ_IPV4;
141a551c94aSIdo Barnea		break;
142a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
143a551c94aSIdo Barnea		desc->type = HASH_RXQ_UDPV6;
144a551c94aSIdo Barnea		break;
145a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
146a551c94aSIdo Barnea		desc->type = HASH_RXQ_TCPV6;
147a551c94aSIdo Barnea		break;
148a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
149a551c94aSIdo Barnea		desc->type = HASH_RXQ_IPV6;
150a551c94aSIdo Barnea		break;
151a551c94aSIdo Barnea	default:
152a551c94aSIdo Barnea		break;
153a551c94aSIdo Barnea	}
154a551c94aSIdo Barnea
155a551c94aSIdo Barnea	/* Set flow values */
156a551c94aSIdo Barnea	switch (fdir_filter->input.flow_type) {
157a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
158a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
159a551c94aSIdo Barnea		desc->src_port = fdir_filter->input.flow.udp4_flow.src_port;
160a551c94aSIdo Barnea		desc->dst_port = fdir_filter->input.flow.udp4_flow.dst_port;
161a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
162a551c94aSIdo Barnea		desc->src_ip[0] = fdir_filter->input.flow.ip4_flow.src_ip;
163a551c94aSIdo Barnea		desc->dst_ip[0] = fdir_filter->input.flow.ip4_flow.dst_ip;
16466937478SHanoh Haim        desc->tos       = fdir_filter->input.flow.ip4_flow.ttl; /* TTL is mapped to TOS TREX_PATCH */
16566937478SHanoh Haim        desc->ip_id     = fdir_filter->input.flow.ip4_flow.ip_id;
16666937478SHanoh Haim        desc->proto     = fdir_filter->input.flow.ip4_flow.proto;
167a551c94aSIdo Barnea		break;
168a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
169a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
170a551c94aSIdo Barnea		desc->src_port = fdir_filter->input.flow.udp6_flow.src_port;
171a551c94aSIdo Barnea		desc->dst_port = fdir_filter->input.flow.udp6_flow.dst_port;
172a551c94aSIdo Barnea		/* Fall through. */
173a551c94aSIdo Barnea	case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
174a551c94aSIdo Barnea		rte_memcpy(desc->src_ip,
175a551c94aSIdo Barnea			   fdir_filter->input.flow.ipv6_flow.src_ip,
176a551c94aSIdo Barnea			   sizeof(desc->src_ip));
177a551c94aSIdo Barnea		rte_memcpy(desc->dst_ip,
178a551c94aSIdo Barnea			   fdir_filter->input.flow.ipv6_flow.dst_ip,
179a551c94aSIdo Barnea			   sizeof(desc->dst_ip));
18066937478SHanoh Haim        desc->tos       = (uint8_t)fdir_filter->input.flow.ipv6_flow.hop_limits;  /* TTL is mapped to TOS - TREX_PATCH */
18166937478SHanoh Haim        desc->ip_id     = (uint8_t)fdir_filter->input.flow.ipv6_flow.flow_label;
18266937478SHanoh Haim        desc->proto     = fdir_filter->input.flow.ipv6_flow.proto;
183a551c94aSIdo Barnea		break;
184a551c94aSIdo Barnea	default:
185a551c94aSIdo Barnea		break;
186a551c94aSIdo Barnea	}
187a551c94aSIdo Barnea}
188a551c94aSIdo Barnea
189a551c94aSIdo Barnea/**
190a551c94aSIdo Barnea * Check if two flow descriptors overlap according to configured mask.
191a551c94aSIdo Barnea *
192a551c94aSIdo Barnea * @param priv
193a551c94aSIdo Barnea *   Private structure that provides flow director mask.
194a551c94aSIdo Barnea * @param desc1
195a551c94aSIdo Barnea *   First flow descriptor to compare.
196a551c94aSIdo Barnea * @param desc2
197a551c94aSIdo Barnea *   Second flow descriptor to compare.
198a551c94aSIdo Barnea *
199a551c94aSIdo Barnea * @return
200a551c94aSIdo Barnea *   Nonzero if descriptors overlap.
201a551c94aSIdo Barnea */
202a551c94aSIdo Barneastatic int
203a551c94aSIdo Barneapriv_fdir_overlap(const struct priv *priv,
204a551c94aSIdo Barnea		  const struct fdir_flow_desc *desc1,
205a551c94aSIdo Barnea		  const struct fdir_flow_desc *desc2)
206a551c94aSIdo Barnea{
207a551c94aSIdo Barnea	const struct rte_eth_fdir_masks *mask =
208a551c94aSIdo Barnea		&priv->dev->data->dev_conf.fdir_conf.mask;
209a551c94aSIdo Barnea	unsigned int i;
210a551c94aSIdo Barnea
211a551c94aSIdo Barnea	if (desc1->type != desc2->type)
212a551c94aSIdo Barnea		return 0;
213a551c94aSIdo Barnea	/* Ignore non masked bits. */
214a551c94aSIdo Barnea	for (i = 0; i != RTE_DIM(desc1->mac); ++i)
215a551c94aSIdo Barnea		if ((desc1->mac[i] & mask->mac_addr_byte_mask) !=
216a551c94aSIdo Barnea		    (desc2->mac[i] & mask->mac_addr_byte_mask))
217a551c94aSIdo Barnea			return 0;
218a551c94aSIdo Barnea	if (((desc1->src_port & mask->src_port_mask) !=
219a551c94aSIdo Barnea	     (desc2->src_port & mask->src_port_mask)) ||
220a551c94aSIdo Barnea	    ((desc1->dst_port & mask->dst_port_mask) !=
221a551c94aSIdo Barnea	     (desc2->dst_port & mask->dst_port_mask)))
222a551c94aSIdo Barnea		return 0;
22366937478SHanoh Haim    if  ( (desc1->tos    != desc2->tos)  ||
22466937478SHanoh Haim          (desc1->ip_id  != desc2->ip_id) ||
22566937478SHanoh Haim          (desc1->proto  != desc2->proto) )
22666937478SHanoh Haim        return 0;
22766937478SHanoh Haim
228a551c94aSIdo Barnea	switch (desc1->type) {
229a551c94aSIdo Barnea	case HASH_RXQ_IPV4:
230a551c94aSIdo Barnea	case HASH_RXQ_UDPV4:
231a551c94aSIdo Barnea	case HASH_RXQ_TCPV4:
232a551c94aSIdo Barnea		if (((desc1->src_ip[0] & mask->ipv4_mask.src_ip) !=
233a551c94aSIdo Barnea		     (desc2->src_ip[0] & mask->ipv4_mask.src_ip)) ||
234a551c94aSIdo Barnea		    ((desc1->dst_ip[0] & mask->ipv4_mask.dst_ip) !=
235be13fd96SHanoh Haim		     (desc2->dst_ip[0] & mask->ipv4_mask.dst_ip)))
236a551c94aSIdo Barnea			return 0;
237a551c94aSIdo Barnea		break;
238a551c94aSIdo Barnea	case HASH_RXQ_IPV6:
239a551c94aSIdo Barnea	case HASH_RXQ_UDPV6:
240a551c94aSIdo Barnea	case HASH_RXQ_TCPV6:
241a551c94aSIdo Barnea		for (i = 0; i != RTE_DIM(desc1->src_ip); ++i)
242a551c94aSIdo Barnea			if (((desc1->src_ip[i] & mask->ipv6_mask.src_ip[i]) !=
243a551c94aSIdo Barnea			     (desc2->src_ip[i] & mask->ipv6_mask.src_ip[i])) ||
244a551c94aSIdo Barnea			    ((desc1->dst_ip[i] & mask->ipv6_mask.dst_ip[i]) !=
245a551c94aSIdo Barnea			     (desc2->dst_ip[i] & mask->ipv6_mask.dst_ip[i])))
246a551c94aSIdo Barnea				return 0;
247a551c94aSIdo Barnea		break;
248a551c94aSIdo Barnea	default:
249a551c94aSIdo Barnea		break;
250a551c94aSIdo Barnea	}
251a551c94aSIdo Barnea	return 1;
252a551c94aSIdo Barnea}
253a551c94aSIdo Barnea
254a551c94aSIdo Barnea/**
255a551c94aSIdo Barnea * Create flow director steering rule for a specific filter.
256a551c94aSIdo Barnea *
257a551c94aSIdo Barnea * @param priv
258a551c94aSIdo Barnea *   Private structure.
259a551c94aSIdo Barnea * @param mlx5_fdir_filter
260a551c94aSIdo Barnea *   Filter to create a steering rule for.
261a551c94aSIdo Barnea * @param fdir_queue
262a551c94aSIdo Barnea *   Flow director queue for matching packets.
263a551c94aSIdo Barnea *
264a551c94aSIdo Barnea * @return
265a551c94aSIdo Barnea *   0 on success, errno value on failure.
266a551c94aSIdo Barnea */
267a551c94aSIdo Barneastatic int
268a551c94aSIdo Barneapriv_fdir_flow_add(struct priv *priv,
269a551c94aSIdo Barnea		   struct mlx5_fdir_filter *mlx5_fdir_filter,
270a551c94aSIdo Barnea		   struct fdir_queue *fdir_queue)
271a551c94aSIdo Barnea{
272a551c94aSIdo Barnea	struct ibv_exp_flow *flow;
273a551c94aSIdo Barnea	struct fdir_flow_desc *desc = &mlx5_fdir_filter->desc;
274a551c94aSIdo Barnea	enum rte_fdir_mode fdir_mode =
275a551c94aSIdo Barnea		priv->dev->data->dev_conf.fdir_conf.mode;
276a551c94aSIdo Barnea	struct rte_eth_fdir_masks *mask =
277a551c94aSIdo Barnea		&priv->dev->data->dev_conf.fdir_conf.mask;
278a551c94aSIdo Barnea	FLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, desc->type));
279a551c94aSIdo Barnea	struct ibv_exp_flow_attr *attr = &data->attr;
280a551c94aSIdo Barnea	uintptr_t spec_offset = (uintptr_t)&data->spec;
281a551c94aSIdo Barnea	struct ibv_exp_flow_spec_eth *spec_eth;
28266937478SHanoh Haim	struct ibv_exp_flow_spec_ipv4_ext *spec_ipv4;
28366937478SHanoh Haim	struct ibv_exp_flow_spec_ipv6_ext *spec_ipv6;
284a551c94aSIdo Barnea	struct ibv_exp_flow_spec_tcp_udp *spec_tcp_udp;
285a551c94aSIdo Barnea	struct mlx5_fdir_filter *iter_fdir_filter;
286a551c94aSIdo Barnea	unsigned int i;
287a551c94aSIdo Barnea
288a551c94aSIdo Barnea	/* Abort if an existing flow overlaps this one to avoid packet
289a551c94aSIdo Barnea	 * duplication, even if it targets another queue. */
290a551c94aSIdo Barnea	LIST_FOREACH(iter_fdir_filter, priv->fdir_filter_list, next)
291a551c94aSIdo Barnea		if ((iter_fdir_filter != mlx5_fdir_filter) &&
292a551c94aSIdo Barnea		    (iter_fdir_filter->flow != NULL) &&
293a551c94aSIdo Barnea		    (priv_fdir_overlap(priv,
294a551c94aSIdo Barnea				       &mlx5_fdir_filter->desc,
29566937478SHanoh Haim				       &iter_fdir_filter->desc))){
29666937478SHanoh Haim            ERROR("overlap rules, please check your rules");
29766937478SHanoh Haim            return EEXIST;
29866937478SHanoh Haim        }
299a551c94aSIdo Barnea
300a551c94aSIdo Barnea	/*
301a551c94aSIdo Barnea	 * No padding must be inserted by the compiler between attr and spec.
302a551c94aSIdo Barnea	 * This layout is expected by libibverbs.
303a551c94aSIdo Barnea	 */
304a551c94aSIdo Barnea	assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec_offset);
305a551c94aSIdo Barnea	priv_flow_attr(priv, attr, sizeof(data), desc->type);
306a551c94aSIdo Barnea
307a551c94aSIdo Barnea	/* Set Ethernet spec */
308a551c94aSIdo Barnea	spec_eth = (struct ibv_exp_flow_spec_eth *)spec_offset;
309a551c94aSIdo Barnea
310a551c94aSIdo Barnea	/* The first specification must be Ethernet. */
311a551c94aSIdo Barnea	assert(spec_eth->type == IBV_EXP_FLOW_SPEC_ETH);
312a551c94aSIdo Barnea	assert(spec_eth->size == sizeof(*spec_eth));
313a551c94aSIdo Barnea
314a551c94aSIdo Barnea	/* VLAN ID */
315a551c94aSIdo Barnea	spec_eth->val.vlan_tag = desc->vlan_tag & mask->vlan_tci_mask;
316a551c94aSIdo Barnea	spec_eth->mask.vlan_tag = mask->vlan_tci_mask;
317a551c94aSIdo Barnea
318a551c94aSIdo Barnea	/* Update priority */
319a551c94aSIdo Barnea	attr->priority = 2;
320a551c94aSIdo Barnea
32166937478SHanoh Haim#ifndef TREX_PATCH
32266937478SHanoh Haim
323a551c94aSIdo Barnea	if (fdir_mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
324a551c94aSIdo Barnea		/* MAC Address */
325a551c94aSIdo Barnea		for (i = 0; i != RTE_DIM(spec_eth->mask.dst_mac); ++i) {
326a551c94aSIdo Barnea			spec_eth->val.dst_mac[i] =
327a551c94aSIdo Barnea				desc->mac[i] & mask->mac_addr_byte_mask;
328a551c94aSIdo Barnea			spec_eth->mask.dst_mac[i] = mask->mac_addr_byte_mask;
329a551c94aSIdo Barnea		}
330a551c94aSIdo Barnea		goto create_flow;
331a551c94aSIdo Barnea	}
33266937478SHanoh Haim#else
33366937478SHanoh Haim    // empty mask means "match everything". This rule will match all packets, no matter what is the ether type
33466937478SHanoh Haim    if (desc->ip_id == 2) {
335768b4f27SHanoh Haim        spec_eth->val.ether_type = 0x0000;
33666937478SHanoh Haim        spec_eth->mask.ether_type = 0x0000;
33766937478SHanoh Haim        goto create_flow;
33866937478SHanoh Haim    }
33966937478SHanoh Haim#endif
34066937478SHanoh Haim
341a551c94aSIdo Barnea
342a551c94aSIdo Barnea	switch (desc->type) {
343a551c94aSIdo Barnea	case HASH_RXQ_IPV4:
344a551c94aSIdo Barnea	case HASH_RXQ_UDPV4:
345a551c94aSIdo Barnea	case HASH_RXQ_TCPV4:
346a551c94aSIdo Barnea		spec_offset += spec_eth->size;
347a551c94aSIdo Barnea
348a551c94aSIdo Barnea		/* Set IP spec */
34966937478SHanoh Haim		spec_ipv4 = (struct ibv_exp_flow_spec_ipv4_ext *)spec_offset;
350a551c94aSIdo Barnea
351a551c94aSIdo Barnea		/* The second specification must be IP. */
35266937478SHanoh Haim		assert(spec_ipv4->type == IBV_EXP_FLOW_SPEC_IPV4_EXT);
353a551c94aSIdo Barnea		assert(spec_ipv4->size == sizeof(*spec_ipv4));
354a551c94aSIdo Barnea
355a551c94aSIdo Barnea		spec_ipv4->val.src_ip =
356a551c94aSIdo Barnea			desc->src_ip[0] & mask->ipv4_mask.src_ip;
357a551c94aSIdo Barnea		spec_ipv4->val.dst_ip =
358a551c94aSIdo Barnea			desc->dst_ip[0] & mask->ipv4_mask.dst_ip;
359a551c94aSIdo Barnea		spec_ipv4->mask.src_ip = mask->ipv4_mask.src_ip;
360a551c94aSIdo Barnea		spec_ipv4->mask.dst_ip = mask->ipv4_mask.dst_ip;
361a551c94aSIdo Barnea
362a551c94aSIdo Barnea		/* Update priority */
363a551c94aSIdo Barnea		attr->priority = 1;
364a551c94aSIdo Barnea
36566937478SHanoh Haim        spec_ipv4->val.proto  = desc->proto & mask->ipv4_mask.proto;
36666937478SHanoh Haim        spec_ipv4->mask.proto = mask->ipv4_mask.proto;
36766937478SHanoh Haim
36866937478SHanoh Haim#ifdef TREX_PATCH
36966937478SHanoh Haim        /* TOS */
37066937478SHanoh Haim        if (desc->ip_id == 1) {
37166937478SHanoh Haim            spec_ipv4->mask.tos = 0x1;
37266937478SHanoh Haim            spec_ipv4->val.tos = 0x1;
37366937478SHanoh Haim        } else {
37466937478SHanoh Haim            spec_ipv4->mask.tos = 0x0;
37566937478SHanoh Haim            spec_ipv4->val.tos = 0x0;
37666937478SHanoh Haim        }
37766937478SHanoh Haim#endif
37866937478SHanoh Haim
37966937478SHanoh Haim
380a551c94aSIdo Barnea		if (desc->type == HASH_RXQ_IPV4)
381a551c94aSIdo Barnea			goto create_flow;
382a551c94aSIdo Barnea
383a551c94aSIdo Barnea		spec_offset += spec_ipv4->size;
384a551c94aSIdo Barnea		break;
385a551c94aSIdo Barnea	case HASH_RXQ_IPV6:
386a551c94aSIdo Barnea	case HASH_RXQ_UDPV6:
387a551c94aSIdo Barnea	case HASH_RXQ_TCPV6:
388a551c94aSIdo Barnea		spec_offset += spec_eth->size;
389a551c94aSIdo Barnea
390a551c94aSIdo Barnea		/* Set IP spec */
39166937478SHanoh Haim		spec_ipv6 = (struct ibv_exp_flow_spec_ipv6_ext *)spec_offset;
392a551c94aSIdo Barnea
393a551c94aSIdo Barnea		/* The second specification must be IP. */
39466937478SHanoh Haim		assert(spec_ipv6->type == IBV_EXP_FLOW_SPEC_IPV6_EXT);
395a551c94aSIdo Barnea		assert(spec_ipv6->size == sizeof(*spec_ipv6));
396a551c94aSIdo Barnea
397a551c94aSIdo Barnea		for (i = 0; i != RTE_DIM(desc->src_ip); ++i) {
398a551c94aSIdo Barnea			((uint32_t *)spec_ipv6->val.src_ip)[i] =
399a551c94aSIdo Barnea				desc->src_ip[i] & mask->ipv6_mask.src_ip[i];
400a551c94aSIdo Barnea			((uint32_t *)spec_ipv6->val.dst_ip)[i] =
401a551c94aSIdo Barnea				desc->dst_ip[i] & mask->ipv6_mask.dst_ip[i];
402a551c94aSIdo Barnea		}
403a551c94aSIdo Barnea		rte_memcpy(spec_ipv6->mask.src_ip,
404a551c94aSIdo Barnea			   mask->ipv6_mask.src_ip,
405a551c94aSIdo Barnea			   sizeof(spec_ipv6->mask.src_ip));
406a551c94aSIdo Barnea		rte_memcpy(spec_ipv6->mask.dst_ip,
407a551c94aSIdo Barnea			   mask->ipv6_mask.dst_ip,
408a551c94aSIdo Barnea			   sizeof(spec_ipv6->mask.dst_ip));
409a551c94aSIdo Barnea
41066937478SHanoh Haim        spec_ipv6->val.next_hdr  = desc->proto & mask->ipv6_mask.proto;
41166937478SHanoh Haim        spec_ipv6->mask.next_hdr = mask->ipv6_mask.proto;
41266937478SHanoh Haim
41366937478SHanoh Haim#ifdef TREX_PATCH
41466937478SHanoh Haim        /* TOS */
41566937478SHanoh Haim        if (desc->ip_id == 1) {
41666937478SHanoh Haim            spec_ipv6->mask.traffic_class = 0x1;
41766937478SHanoh Haim            spec_ipv6->val.traffic_class = 0x1;
41866937478SHanoh Haim        } else {
41966937478SHanoh Haim            spec_ipv6->mask.traffic_class = 0;
42066937478SHanoh Haim            spec_ipv6->val.traffic_class = 0;
42166937478SHanoh Haim        }
42266937478SHanoh Haim#endif
42366937478SHanoh Haim
424a551c94aSIdo Barnea		/* Update priority */
425a551c94aSIdo Barnea		attr->priority = 1;
426a551c94aSIdo Barnea
427a551c94aSIdo Barnea		if (desc->type == HASH_RXQ_IPV6)
428a551c94aSIdo Barnea			goto create_flow;
429a551c94aSIdo Barnea
430a551c94aSIdo Barnea		spec_offset += spec_ipv6->size;
431a551c94aSIdo Barnea		break;
432a551c94aSIdo Barnea	default:
433a551c94aSIdo Barnea		ERROR("invalid flow attribute type");
434a551c94aSIdo Barnea		return EINVAL;
435a551c94aSIdo Barnea	}
436a551c94aSIdo Barnea
437a551c94aSIdo Barnea	/* Set TCP/UDP flow specification. */
438a551c94aSIdo Barnea	spec_tcp_udp = (struct ibv_exp_flow_spec_tcp_udp *)spec_offset;
439a551c94aSIdo Barnea
440a551c94aSIdo Barnea	/* The third specification must be TCP/UDP. */
441a551c94aSIdo Barnea	assert(spec_tcp_udp->type == IBV_EXP_FLOW_SPEC_TCP ||
442a551c94aSIdo Barnea	       spec_tcp_udp->type == IBV_EXP_FLOW_SPEC_UDP);
443a551c94aSIdo Barnea	assert(spec_tcp_udp->size == sizeof(*spec_tcp_udp));
444a551c94aSIdo Barnea
445a551c94aSIdo Barnea	spec_tcp_udp->val.src_port = desc->src_port & mask->src_port_mask;
446a551c94aSIdo Barnea	spec_tcp_udp->val.dst_port = desc->dst_port & mask->dst_port_mask;
447a551c94aSIdo Barnea	spec_tcp_udp->mask.src_port = mask->src_port_mask;
448a551c94aSIdo Barnea	spec_tcp_udp->mask.dst_port = mask->dst_port_mask;
449a551c94aSIdo Barnea
450a551c94aSIdo Barnea	/* Update priority */
451a551c94aSIdo Barnea	attr->priority = 0;
452a551c94aSIdo Barnea
453a551c94aSIdo Barneacreate_flow:
454a551c94aSIdo Barnea
455a551c94aSIdo Barnea	errno = 0;
456a551c94aSIdo Barnea	flow = ibv_exp_create_flow(fdir_queue->qp, attr);
457a551c94aSIdo Barnea	if (flow == NULL) {
458a551c94aSIdo Barnea		/* It's not clear whether errno is always set in this case. */
459a551c94aSIdo Barnea		ERROR("%p: flow director configuration failed, errno=%d: %s",
460a551c94aSIdo Barnea		      (void *)priv, errno,
461a551c94aSIdo Barnea		      (errno ? strerror(errno) : "Unknown error"));
462a551c94aSIdo Barnea		if (errno)
463a551c94aSIdo Barnea			return errno;
464a551c94aSIdo Barnea		return EINVAL;
465a551c94aSIdo Barnea	}
466a551c94aSIdo Barnea
467a551c94aSIdo Barnea	DEBUG("%p: added flow director rule (%p)", (void *)priv, (void *)flow);
468a551c94aSIdo Barnea	mlx5_fdir_filter->flow = flow;
469a551c94aSIdo Barnea	return 0;
470a551c94aSIdo Barnea}
471a551c94aSIdo Barnea
472be13fd96SHanoh Haim/**
473be13fd96SHanoh Haim * Destroy a flow director queue.
474be13fd96SHanoh Haim *
475be13fd96SHanoh Haim * @param fdir_queue
476be13fd96SHanoh Haim *   Flow director queue to be destroyed.
477be13fd96SHanoh Haim */
478be13fd96SHanoh Haimvoid
479be13fd96SHanoh Haimpriv_fdir_queue_destroy(struct priv *priv, struct fdir_queue *fdir_queue)
480be13fd96SHanoh Haim{
481be13fd96SHanoh Haim	struct mlx5_fdir_filter *fdir_filter;
482be13fd96SHanoh Haim
483be13fd96SHanoh Haim	/* Disable filter flows still applying to this queue. */
484be13fd96SHanoh Haim	LIST_FOREACH(fdir_filter, priv->fdir_filter_list, next) {
485be13fd96SHanoh Haim		unsigned int idx = fdir_filter->queue;
486be13fd96SHanoh Haim		struct rxq_ctrl *rxq_ctrl =
487be13fd96SHanoh Haim			container_of((*priv->rxqs)[idx], struct rxq_ctrl, rxq);
488be13fd96SHanoh Haim
489be13fd96SHanoh Haim		assert(idx < priv->rxqs_n);
490be13fd96SHanoh Haim		if (fdir_queue == rxq_ctrl->fdir_queue &&
491be13fd96SHanoh Haim		    fdir_filter->flow != NULL) {
492be13fd96SHanoh Haim			claim_zero(ibv_exp_destroy_flow(fdir_filter->flow));
493be13fd96SHanoh Haim			fdir_filter->flow = NULL;
494be13fd96SHanoh Haim		}
495be13fd96SHanoh Haim	}
496be13fd96SHanoh Haim	assert(fdir_queue->qp);
497be13fd96SHanoh Haim	claim_zero(ibv_destroy_qp(fdir_queue->qp));
498be13fd96SHanoh Haim	assert(fdir_queue->ind_table);
499be13fd96SHanoh Haim	claim_zero(ibv_exp_destroy_rwq_ind_table(fdir_queue->ind_table));
500be13fd96SHanoh Haim	if (fdir_queue->wq)
501be13fd96SHanoh Haim		claim_zero(ibv_exp_destroy_wq(fdir_queue->wq));
502be13fd96SHanoh Haim	if (fdir_queue->cq)
503be13fd96SHanoh Haim		claim_zero(ibv_destroy_cq(fdir_queue->cq));
504be13fd96SHanoh Haim#ifndef NDEBUG
505be13fd96SHanoh Haim	memset(fdir_queue, 0x2a, sizeof(*fdir_queue));
506be13fd96SHanoh Haim#endif
507be13fd96SHanoh Haim	rte_free(fdir_queue);
508be13fd96SHanoh Haim}
509be13fd96SHanoh Haim
510be13fd96SHanoh Haim/**
511be13fd96SHanoh Haim * Create a flow director queue.
512be13fd96SHanoh Haim *
513be13fd96SHanoh Haim * @param priv
514be13fd96SHanoh Haim *   Private structure.
515be13fd96SHanoh Haim * @param wq
516be13fd96SHanoh Haim *   Work queue to route matched packets to, NULL if one needs to
517be13fd96SHanoh Haim *   be created.
518be13fd96SHanoh Haim *
519be13fd96SHanoh Haim * @return
520be13fd96SHanoh Haim *   Related flow director queue on success, NULL otherwise.
521be13fd96SHanoh Haim */
522be13fd96SHanoh Haimstatic struct fdir_queue *
523be13fd96SHanoh Haimpriv_fdir_queue_create(struct priv *priv, struct ibv_exp_wq *wq,
524be13fd96SHanoh Haim		       unsigned int socket)
525be13fd96SHanoh Haim{
526be13fd96SHanoh Haim	struct fdir_queue *fdir_queue;
527be13fd96SHanoh Haim
528be13fd96SHanoh Haim	fdir_queue = rte_calloc_socket(__func__, 1, sizeof(*fdir_queue),
529be13fd96SHanoh Haim				       0, socket);
530be13fd96SHanoh Haim	if (!fdir_queue) {
531be13fd96SHanoh Haim		ERROR("cannot allocate flow director queue");
532be13fd96SHanoh Haim		return NULL;
533be13fd96SHanoh Haim	}
534be13fd96SHanoh Haim	assert(priv->pd);
535be13fd96SHanoh Haim	assert(priv->ctx);
536be13fd96SHanoh Haim	if (!wq) {
537be13fd96SHanoh Haim		fdir_queue->cq = ibv_exp_create_cq(
538be13fd96SHanoh Haim			priv->ctx, 1, NULL, NULL, 0,
539be13fd96SHanoh Haim			&(struct ibv_exp_cq_init_attr){
540be13fd96SHanoh Haim				.comp_mask = 0,
541be13fd96SHanoh Haim			});
542be13fd96SHanoh Haim		if (!fdir_queue->cq) {
543be13fd96SHanoh Haim			ERROR("cannot create flow director CQ");
544be13fd96SHanoh Haim			goto error;
545be13fd96SHanoh Haim		}
546be13fd96SHanoh Haim		fdir_queue->wq = ibv_exp_create_wq(
547be13fd96SHanoh Haim			priv->ctx,
548be13fd96SHanoh Haim			&(struct ibv_exp_wq_init_attr){
549be13fd96SHanoh Haim				.wq_type = IBV_EXP_WQT_RQ,
550be13fd96SHanoh Haim				.max_recv_wr = 1,
551be13fd96SHanoh Haim				.max_recv_sge = 1,
552be13fd96SHanoh Haim				.pd = priv->pd,
553be13fd96SHanoh Haim				.cq = fdir_queue->cq,
554be13fd96SHanoh Haim			});
555be13fd96SHanoh Haim		if (!fdir_queue->wq) {
556be13fd96SHanoh Haim			ERROR("cannot create flow director WQ");
557be13fd96SHanoh Haim			goto error;
558be13fd96SHanoh Haim		}
559be13fd96SHanoh Haim		wq = fdir_queue->wq;
560be13fd96SHanoh Haim	}
561be13fd96SHanoh Haim	fdir_queue->ind_table = ibv_exp_create_rwq_ind_table(
562be13fd96SHanoh Haim		priv->ctx,
563be13fd96SHanoh Haim		&(struct ibv_exp_rwq_ind_table_init_attr){
564be13fd96SHanoh Haim			.pd = priv->pd,
565be13fd96SHanoh Haim			.log_ind_tbl_size = 0,
566be13fd96SHanoh Haim			.ind_tbl = &wq,
567be13fd96SHanoh Haim			.comp_mask = 0,
568be13fd96SHanoh Haim		});
569be13fd96SHanoh Haim	if (!fdir_queue->ind_table) {
570be13fd96SHanoh Haim		ERROR("cannot create flow director indirection table");
571be13fd96SHanoh Haim		goto error;
572be13fd96SHanoh Haim	}
573be13fd96SHanoh Haim	fdir_queue->qp = ibv_exp_create_qp(
574be13fd96SHanoh Haim		priv->ctx,
575be13fd96SHanoh Haim		&(struct ibv_exp_qp_init_attr){
576be13fd96SHanoh Haim			.qp_type = IBV_QPT_RAW_PACKET,
577be13fd96SHanoh Haim			.comp_mask =
578be13fd96SHanoh Haim				IBV_EXP_QP_INIT_ATTR_PD |
579be13fd96SHanoh Haim				IBV_EXP_QP_INIT_ATTR_PORT |
580be13fd96SHanoh Haim				IBV_EXP_QP_INIT_ATTR_RX_HASH,
581be13fd96SHanoh Haim			.pd = priv->pd,
582be13fd96SHanoh Haim			.rx_hash_conf = &(struct ibv_exp_rx_hash_conf){
583be13fd96SHanoh Haim				.rx_hash_function =
584be13fd96SHanoh Haim					IBV_EXP_RX_HASH_FUNC_TOEPLITZ,
585be13fd96SHanoh Haim				.rx_hash_key_len = rss_hash_default_key_len,
586be13fd96SHanoh Haim				.rx_hash_key = rss_hash_default_key,
587be13fd96SHanoh Haim				.rx_hash_fields_mask = 0,
588be13fd96SHanoh Haim				.rwq_ind_tbl = fdir_queue->ind_table,
589be13fd96SHanoh Haim			},
590be13fd96SHanoh Haim			.port_num = priv->port,
591be13fd96SHanoh Haim		});
592be13fd96SHanoh Haim	if (!fdir_queue->qp) {
593be13fd96SHanoh Haim		ERROR("cannot create flow director hash RX QP");
594be13fd96SHanoh Haim		goto error;
595be13fd96SHanoh Haim	}
596be13fd96SHanoh Haim	return fdir_queue;
597be13fd96SHanoh Haimerror:
598be13fd96SHanoh Haim	assert(fdir_queue);
599be13fd96SHanoh Haim	assert(!fdir_queue->qp);
600be13fd96SHanoh Haim	if (fdir_queue->ind_table)
601be13fd96SHanoh Haim		claim_zero(ibv_exp_destroy_rwq_ind_table
602be13fd96SHanoh Haim			   (fdir_queue->ind_table));
603be13fd96SHanoh Haim	if (fdir_queue->wq)
604be13fd96SHanoh Haim		claim_zero(ibv_exp_destroy_wq(fdir_queue->wq));
605be13fd96SHanoh Haim	if (fdir_queue->cq)
606be13fd96SHanoh Haim		claim_zero(ibv_destroy_cq(fdir_queue->cq));
607be13fd96SHanoh Haim	rte_free(fdir_queue);
608be13fd96SHanoh Haim	return NULL;
609be13fd96SHanoh Haim}
610be13fd96SHanoh Haim
611a551c94aSIdo Barnea/**
612a551c94aSIdo Barnea * Get flow director queue for a specific RX queue, create it in case
613a551c94aSIdo Barnea * it does not exist.
614a551c94aSIdo Barnea *
615a551c94aSIdo Barnea * @param priv
616a551c94aSIdo Barnea *   Private structure.
617a551c94aSIdo Barnea * @param idx
618a551c94aSIdo Barnea *   RX queue index.
619a551c94aSIdo Barnea *
620a551c94aSIdo Barnea * @return
621a551c94aSIdo Barnea *   Related flow director queue on success, NULL otherwise.
622a551c94aSIdo Barnea */
623a551c94aSIdo Barneastatic struct fdir_queue *
624a551c94aSIdo Barneapriv_get_fdir_queue(struct priv *priv, uint16_t idx)
625a551c94aSIdo Barnea{
626a551c94aSIdo Barnea	struct rxq_ctrl *rxq_ctrl =
627a551c94aSIdo Barnea		container_of((*priv->rxqs)[idx], struct rxq_ctrl, rxq);
628be13fd96SHanoh Haim	struct fdir_queue *fdir_queue = rxq_ctrl->fdir_queue;
629a551c94aSIdo Barnea
630be13fd96SHanoh Haim	assert(rxq_ctrl->wq);
631be13fd96SHanoh Haim	if (fdir_queue == NULL) {
632be13fd96SHanoh Haim		fdir_queue = priv_fdir_queue_create(priv, rxq_ctrl->wq,
633be13fd96SHanoh Haim						    rxq_ctrl->socket);
634be13fd96SHanoh Haim		rxq_ctrl->fdir_queue = fdir_queue;
635a551c94aSIdo Barnea	}
636a551c94aSIdo Barnea	return fdir_queue;
637be13fd96SHanoh Haim}
638a551c94aSIdo Barnea
639be13fd96SHanoh Haim/**
640be13fd96SHanoh Haim * Get or flow director drop queue. Create it if it does not exist.
641be13fd96SHanoh Haim *
642be13fd96SHanoh Haim * @param priv
643be13fd96SHanoh Haim *   Private structure.
644be13fd96SHanoh Haim *
645be13fd96SHanoh Haim * @return
646be13fd96SHanoh Haim *   Flow director drop queue on success, NULL otherwise.
647be13fd96SHanoh Haim */
648be13fd96SHanoh Haimstatic struct fdir_queue *
649be13fd96SHanoh Haimpriv_get_fdir_drop_queue(struct priv *priv)
650be13fd96SHanoh Haim{
651be13fd96SHanoh Haim	struct fdir_queue *fdir_queue = priv->fdir_drop_queue;
652a551c94aSIdo Barnea
653be13fd96SHanoh Haim	if (fdir_queue == NULL) {
654be13fd96SHanoh Haim		unsigned int socket = SOCKET_ID_ANY;
655be13fd96SHanoh Haim
656be13fd96SHanoh Haim		/* Select a known NUMA socket if possible. */
657be13fd96SHanoh Haim		if (priv->rxqs_n && (*priv->rxqs)[0])
658be13fd96SHanoh Haim			socket = container_of((*priv->rxqs)[0],
659be13fd96SHanoh Haim					      struct rxq_ctrl, rxq)->socket;
660be13fd96SHanoh Haim		fdir_queue = priv_fdir_queue_create(priv, NULL, socket);
661be13fd96SHanoh Haim		priv->fdir_drop_queue = fdir_queue;
662be13fd96SHanoh Haim	}
663be13fd96SHanoh Haim	return fdir_queue;
664a551c94aSIdo Barnea}
665a551c94aSIdo Barnea
666a551c94aSIdo Barnea/**
667a551c94aSIdo Barnea * Enable flow director filter and create steering rules.
668a551c94aSIdo Barnea *
669a551c94aSIdo Barnea * @param priv
670a551c94aSIdo Barnea *   Private structure.
671a551c94aSIdo Barnea * @param mlx5_fdir_filter
672a551c94aSIdo Barnea *   Filter to create steering rule for.
673a551c94aSIdo Barnea *
674a551c94aSIdo Barnea * @return
675a551c94aSIdo Barnea *   0 on success, errno value on failure.
676a551c94aSIdo Barnea */
677a551c94aSIdo Barneastatic int
678a551c94aSIdo Barneapriv_fdir_filter_enable(struct priv *priv,
679a551c94aSIdo Barnea			struct mlx5_fdir_filter *mlx5_fdir_filter)
680a551c94aSIdo Barnea{
681a551c94aSIdo Barnea	struct fdir_queue *fdir_queue;
682a551c94aSIdo Barnea
683a551c94aSIdo Barnea	/* Check if flow already exists. */
684a551c94aSIdo Barnea	if (mlx5_fdir_filter->flow != NULL)
685a551c94aSIdo Barnea		return 0;
686a551c94aSIdo Barnea
687a551c94aSIdo Barnea	/* Get fdir_queue for specific queue. */
688be13fd96SHanoh Haim	if (mlx5_fdir_filter->behavior == RTE_ETH_FDIR_REJECT)
689be13fd96SHanoh Haim		fdir_queue = priv_get_fdir_drop_queue(priv);
690be13fd96SHanoh Haim	else
691be13fd96SHanoh Haim		fdir_queue = priv_get_fdir_queue(priv,
692be13fd96SHanoh Haim						 mlx5_fdir_filter->queue);
693a551c94aSIdo Barnea
694a551c94aSIdo Barnea	if (fdir_queue == NULL) {
695a551c94aSIdo Barnea		ERROR("failed to create flow director rxq for queue %d",
696a551c94aSIdo Barnea		      mlx5_fdir_filter->queue);
697a551c94aSIdo Barnea		return EINVAL;
698a551c94aSIdo Barnea	}
699a551c94aSIdo Barnea
700a551c94aSIdo Barnea	/* Create flow */
701a551c94aSIdo Barnea	return priv_fdir_flow_add(priv, mlx5_fdir_filter, fdir_queue);
702a551c94aSIdo Barnea}
703a551c94aSIdo Barnea
704a551c94aSIdo Barnea/**
705a551c94aSIdo Barnea * Initialize flow director filters list.
706a551c94aSIdo Barnea *
707a551c94aSIdo Barnea * @param priv
708a551c94aSIdo Barnea *   Private structure.
709a551c94aSIdo Barnea *
710a551c94aSIdo Barnea * @return
711a551c94aSIdo Barnea *   0 on success, errno value on failure.
712a551c94aSIdo Barnea */
713a551c94aSIdo Barneaint
714a551c94aSIdo Barneafdir_init_filters_list(struct priv *priv)
715a551c94aSIdo Barnea{
716a551c94aSIdo Barnea	/* Filter list initialization should be done only once. */
717a551c94aSIdo Barnea	if (priv->fdir_filter_list)
718a551c94aSIdo Barnea		return 0;
719a551c94aSIdo Barnea
720a551c94aSIdo Barnea	/* Create filters list. */
721a551c94aSIdo Barnea	priv->fdir_filter_list =
722a551c94aSIdo Barnea		rte_calloc(__func__, 1, sizeof(*priv->fdir_filter_list), 0);
723a551c94aSIdo Barnea
724a551c94aSIdo Barnea	if (priv->fdir_filter_list == NULL) {
725a551c94aSIdo Barnea		int err = ENOMEM;
726a551c94aSIdo Barnea
727a551c94aSIdo Barnea		ERROR("cannot allocate flow director filter list: %s",
728a551c94aSIdo Barnea		      strerror(err));
729a551c94aSIdo Barnea		return err;
730a551c94aSIdo Barnea	}
731a551c94aSIdo Barnea
732a551c94aSIdo Barnea	LIST_INIT(priv->fdir_filter_list);
733a551c94aSIdo Barnea
734a551c94aSIdo Barnea	return 0;
735a551c94aSIdo Barnea}
736a551c94aSIdo Barnea
737a551c94aSIdo Barnea/**
738a551c94aSIdo Barnea * Flush all filters.
739a551c94aSIdo Barnea *
740a551c94aSIdo Barnea * @param priv
741a551c94aSIdo Barnea *   Private structure.
742a551c94aSIdo Barnea */
743a551c94aSIdo Barneastatic void
744a551c94aSIdo Barneapriv_fdir_filter_flush(struct priv *priv)
745a551c94aSIdo Barnea{
746a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
747a551c94aSIdo Barnea
748a551c94aSIdo Barnea	while ((mlx5_fdir_filter = LIST_FIRST(priv->fdir_filter_list))) {
749a551c94aSIdo Barnea		struct ibv_exp_flow *flow = mlx5_fdir_filter->flow;
750a551c94aSIdo Barnea
751a551c94aSIdo Barnea		DEBUG("%p: flushing flow director filter %p",
752a551c94aSIdo Barnea		      (void *)priv, (void *)mlx5_fdir_filter);
753a551c94aSIdo Barnea		LIST_REMOVE(mlx5_fdir_filter, next);
754a551c94aSIdo Barnea		if (flow != NULL)
755a551c94aSIdo Barnea			claim_zero(ibv_exp_destroy_flow(flow));
756a551c94aSIdo Barnea		rte_free(mlx5_fdir_filter);
757a551c94aSIdo Barnea	}
758a551c94aSIdo Barnea}
759a551c94aSIdo Barnea
760a551c94aSIdo Barnea/**
761a551c94aSIdo Barnea * Remove all flow director filters and delete list.
762a551c94aSIdo Barnea *
763a551c94aSIdo Barnea * @param priv
764a551c94aSIdo Barnea *   Private structure.
765a551c94aSIdo Barnea */
766a551c94aSIdo Barneavoid
767a551c94aSIdo Barneapriv_fdir_delete_filters_list(struct priv *priv)
768a551c94aSIdo Barnea{
769a551c94aSIdo Barnea	priv_fdir_filter_flush(priv);
770a551c94aSIdo Barnea	rte_free(priv->fdir_filter_list);
771a551c94aSIdo Barnea	priv->fdir_filter_list = NULL;
772a551c94aSIdo Barnea}
773a551c94aSIdo Barnea
774a551c94aSIdo Barnea/**
775a551c94aSIdo Barnea * Disable flow director, remove all steering rules.
776a551c94aSIdo Barnea *
777a551c94aSIdo Barnea * @param priv
778a551c94aSIdo Barnea *   Private structure.
779a551c94aSIdo Barnea */
780a551c94aSIdo Barneavoid
781a551c94aSIdo Barneapriv_fdir_disable(struct priv *priv)
782a551c94aSIdo Barnea{
783a551c94aSIdo Barnea	unsigned int i;
784a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
785a551c94aSIdo Barnea
786a551c94aSIdo Barnea	/* Run on every flow director filter and destroy flow handle. */
787a551c94aSIdo Barnea	LIST_FOREACH(mlx5_fdir_filter, priv->fdir_filter_list, next) {
788a551c94aSIdo Barnea		struct ibv_exp_flow *flow;
789a551c94aSIdo Barnea
790a551c94aSIdo Barnea		/* Only valid elements should be in the list */
791a551c94aSIdo Barnea		assert(mlx5_fdir_filter != NULL);
792a551c94aSIdo Barnea		flow = mlx5_fdir_filter->flow;
793a551c94aSIdo Barnea
794a551c94aSIdo Barnea		/* Destroy flow handle */
795a551c94aSIdo Barnea		if (flow != NULL) {
796a551c94aSIdo Barnea			claim_zero(ibv_exp_destroy_flow(flow));
797a551c94aSIdo Barnea			mlx5_fdir_filter->flow = NULL;
798a551c94aSIdo Barnea		}
799a551c94aSIdo Barnea	}
800a551c94aSIdo Barnea
801be13fd96SHanoh Haim	/* Destroy flow director context in each RX queue. */
802a551c94aSIdo Barnea	for (i = 0; (i != priv->rxqs_n); i++) {
803a551c94aSIdo Barnea		struct rxq_ctrl *rxq_ctrl =
804a551c94aSIdo Barnea			container_of((*priv->rxqs)[i], struct rxq_ctrl, rxq);
805a551c94aSIdo Barnea
806be13fd96SHanoh Haim		if (!rxq_ctrl->fdir_queue)
807be13fd96SHanoh Haim			continue;
808be13fd96SHanoh Haim		priv_fdir_queue_destroy(priv, rxq_ctrl->fdir_queue);
809be13fd96SHanoh Haim		rxq_ctrl->fdir_queue = NULL;
810be13fd96SHanoh Haim	}
811be13fd96SHanoh Haim	if (priv->fdir_drop_queue) {
812be13fd96SHanoh Haim		priv_fdir_queue_destroy(priv, priv->fdir_drop_queue);
813be13fd96SHanoh Haim		priv->fdir_drop_queue = NULL;
814a551c94aSIdo Barnea	}
815a551c94aSIdo Barnea}
816a551c94aSIdo Barnea
817a551c94aSIdo Barnea/**
818a551c94aSIdo Barnea * Enable flow director, create steering rules.
819a551c94aSIdo Barnea *
820a551c94aSIdo Barnea * @param priv
821a551c94aSIdo Barnea *   Private structure.
822a551c94aSIdo Barnea */
823a551c94aSIdo Barneavoid
824a551c94aSIdo Barneapriv_fdir_enable(struct priv *priv)
825a551c94aSIdo Barnea{
826a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
827a551c94aSIdo Barnea
828a551c94aSIdo Barnea	/* Run on every fdir filter and create flow handle */
829a551c94aSIdo Barnea	LIST_FOREACH(mlx5_fdir_filter, priv->fdir_filter_list, next) {
830a551c94aSIdo Barnea		/* Only valid elements should be in the list */
831a551c94aSIdo Barnea		assert(mlx5_fdir_filter != NULL);
832a551c94aSIdo Barnea
833a551c94aSIdo Barnea		priv_fdir_filter_enable(priv, mlx5_fdir_filter);
834a551c94aSIdo Barnea	}
835a551c94aSIdo Barnea}
836a551c94aSIdo Barnea
837a551c94aSIdo Barnea/**
838a551c94aSIdo Barnea * Find specific filter in list.
839a551c94aSIdo Barnea *
840a551c94aSIdo Barnea * @param priv
841a551c94aSIdo Barnea *   Private structure.
842a551c94aSIdo Barnea * @param fdir_filter
843a551c94aSIdo Barnea *   Flow director filter to find.
844a551c94aSIdo Barnea *
845a551c94aSIdo Barnea * @return
846a551c94aSIdo Barnea *   Filter element if found, otherwise NULL.
847a551c94aSIdo Barnea */
848a551c94aSIdo Barneastatic struct mlx5_fdir_filter *
849a551c94aSIdo Barneapriv_find_filter_in_list(struct priv *priv,
850a551c94aSIdo Barnea			 const struct rte_eth_fdir_filter *fdir_filter)
851a551c94aSIdo Barnea{
852a551c94aSIdo Barnea	struct fdir_flow_desc desc;
853a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
854a551c94aSIdo Barnea	enum rte_fdir_mode fdir_mode = priv->dev->data->dev_conf.fdir_conf.mode;
855a551c94aSIdo Barnea
856a551c94aSIdo Barnea	/* Get flow director filter to look for. */
857a551c94aSIdo Barnea	fdir_filter_to_flow_desc(fdir_filter, &desc, fdir_mode);
858a551c94aSIdo Barnea
859a551c94aSIdo Barnea	/* Look for the requested element. */
860a551c94aSIdo Barnea	LIST_FOREACH(mlx5_fdir_filter, priv->fdir_filter_list, next) {
861a551c94aSIdo Barnea		/* Only valid elements should be in the list. */
862a551c94aSIdo Barnea		assert(mlx5_fdir_filter != NULL);
863a551c94aSIdo Barnea
864a551c94aSIdo Barnea		/* Return matching filter. */
865a551c94aSIdo Barnea		if (!memcmp(&desc, &mlx5_fdir_filter->desc, sizeof(desc)))
866a551c94aSIdo Barnea			return mlx5_fdir_filter;
867a551c94aSIdo Barnea	}
868a551c94aSIdo Barnea
869a551c94aSIdo Barnea	/* Filter not found */
870a551c94aSIdo Barnea	return NULL;
871a551c94aSIdo Barnea}
872a551c94aSIdo Barnea
873a551c94aSIdo Barnea/**
874a551c94aSIdo Barnea * Add new flow director filter and store it in list.
875a551c94aSIdo Barnea *
876a551c94aSIdo Barnea * @param priv
877a551c94aSIdo Barnea *   Private structure.
878a551c94aSIdo Barnea * @param fdir_filter
879a551c94aSIdo Barnea *   Flow director filter to add.
880a551c94aSIdo Barnea *
881a551c94aSIdo Barnea * @return
882a551c94aSIdo Barnea *   0 on success, errno value on failure.
883a551c94aSIdo Barnea */
884a551c94aSIdo Barneastatic int
885a551c94aSIdo Barneapriv_fdir_filter_add(struct priv *priv,
886a551c94aSIdo Barnea		     const struct rte_eth_fdir_filter *fdir_filter)
887a551c94aSIdo Barnea{
888a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
889a551c94aSIdo Barnea	enum rte_fdir_mode fdir_mode = priv->dev->data->dev_conf.fdir_conf.mode;
890a551c94aSIdo Barnea	int err = 0;
891a551c94aSIdo Barnea
892a551c94aSIdo Barnea	/* Validate queue number. */
893a551c94aSIdo Barnea	if (fdir_filter->action.rx_queue >= priv->rxqs_n) {
894a551c94aSIdo Barnea		ERROR("invalid queue number %d", fdir_filter->action.rx_queue);
895a551c94aSIdo Barnea		return EINVAL;
896a551c94aSIdo Barnea	}
897a551c94aSIdo Barnea
898a551c94aSIdo Barnea	/* Duplicate filters are currently unsupported. */
899a551c94aSIdo Barnea	mlx5_fdir_filter = priv_find_filter_in_list(priv, fdir_filter);
900a551c94aSIdo Barnea	if (mlx5_fdir_filter != NULL) {
90166937478SHanoh Haim#ifndef TREX_PATCH
902a551c94aSIdo Barnea		ERROR("filter already exists");
90366937478SHanoh Haim#endif
90466937478SHanoh Haim		return EEXIST;
905a551c94aSIdo Barnea	}
906a551c94aSIdo Barnea
907a551c94aSIdo Barnea	/* Create new flow director filter. */
908a551c94aSIdo Barnea	mlx5_fdir_filter =
909a551c94aSIdo Barnea		rte_calloc(__func__, 1, sizeof(*mlx5_fdir_filter), 0);
910a551c94aSIdo Barnea	if (mlx5_fdir_filter == NULL) {
911a551c94aSIdo Barnea		err = ENOMEM;
912a551c94aSIdo Barnea		ERROR("cannot allocate flow director filter: %s",
913a551c94aSIdo Barnea		      strerror(err));
914a551c94aSIdo Barnea		return err;
915a551c94aSIdo Barnea	}
916a551c94aSIdo Barnea
917be13fd96SHanoh Haim	/* Set action parameters. */
918a551c94aSIdo Barnea	mlx5_fdir_filter->queue = fdir_filter->action.rx_queue;
919be13fd96SHanoh Haim	mlx5_fdir_filter->behavior = fdir_filter->action.behavior;
920a551c94aSIdo Barnea
921a551c94aSIdo Barnea	/* Convert to mlx5 filter descriptor. */
922a551c94aSIdo Barnea	fdir_filter_to_flow_desc(fdir_filter,
923a551c94aSIdo Barnea				 &mlx5_fdir_filter->desc, fdir_mode);
924a551c94aSIdo Barnea
925a551c94aSIdo Barnea	/* Insert new filter into list. */
926a551c94aSIdo Barnea	LIST_INSERT_HEAD(priv->fdir_filter_list, mlx5_fdir_filter, next);
927a551c94aSIdo Barnea
928a551c94aSIdo Barnea	DEBUG("%p: flow director filter %p added",
929a551c94aSIdo Barnea	      (void *)priv, (void *)mlx5_fdir_filter);
930a551c94aSIdo Barnea
931a551c94aSIdo Barnea	/* Enable filter immediately if device is started. */
932a551c94aSIdo Barnea	if (priv->started)
933a551c94aSIdo Barnea		err = priv_fdir_filter_enable(priv, mlx5_fdir_filter);
934a551c94aSIdo Barnea
935a551c94aSIdo Barnea	return err;
936a551c94aSIdo Barnea}
937a551c94aSIdo Barnea
938a551c94aSIdo Barnea/**
939a551c94aSIdo Barnea * Update queue for specific filter.
940a551c94aSIdo Barnea *
941a551c94aSIdo Barnea * @param priv
942a551c94aSIdo Barnea *   Private structure.
943a551c94aSIdo Barnea * @param fdir_filter
944a551c94aSIdo Barnea *   Filter to be updated.
945a551c94aSIdo Barnea *
946a551c94aSIdo Barnea * @return
947a551c94aSIdo Barnea *   0 on success, errno value on failure.
948a551c94aSIdo Barnea */
949a551c94aSIdo Barneastatic int
950a551c94aSIdo Barneapriv_fdir_filter_update(struct priv *priv,
951a551c94aSIdo Barnea			const struct rte_eth_fdir_filter *fdir_filter)
952a551c94aSIdo Barnea{
953a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
954a551c94aSIdo Barnea
955a551c94aSIdo Barnea	/* Validate queue number. */
956a551c94aSIdo Barnea	if (fdir_filter->action.rx_queue >= priv->rxqs_n) {
957a551c94aSIdo Barnea		ERROR("invalid queue number %d", fdir_filter->action.rx_queue);
958a551c94aSIdo Barnea		return EINVAL;
959a551c94aSIdo Barnea	}
960a551c94aSIdo Barnea
961a551c94aSIdo Barnea	mlx5_fdir_filter = priv_find_filter_in_list(priv, fdir_filter);
962a551c94aSIdo Barnea	if (mlx5_fdir_filter != NULL) {
963a551c94aSIdo Barnea		struct ibv_exp_flow *flow = mlx5_fdir_filter->flow;
964a551c94aSIdo Barnea		int err = 0;
965a551c94aSIdo Barnea
966a551c94aSIdo Barnea		/* Update queue number. */
967a551c94aSIdo Barnea		mlx5_fdir_filter->queue = fdir_filter->action.rx_queue;
968a551c94aSIdo Barnea
969a551c94aSIdo Barnea		/* Destroy flow handle. */
970a551c94aSIdo Barnea		if (flow != NULL) {
971a551c94aSIdo Barnea			claim_zero(ibv_exp_destroy_flow(flow));
972a551c94aSIdo Barnea			mlx5_fdir_filter->flow = NULL;
973a551c94aSIdo Barnea		}
974a551c94aSIdo Barnea		DEBUG("%p: flow director filter %p updated",
975a551c94aSIdo Barnea		      (void *)priv, (void *)mlx5_fdir_filter);
976a551c94aSIdo Barnea
977a551c94aSIdo Barnea		/* Enable filter if device is started. */
978a551c94aSIdo Barnea		if (priv->started)
979a551c94aSIdo Barnea			err = priv_fdir_filter_enable(priv, mlx5_fdir_filter);
980a551c94aSIdo Barnea
981a551c94aSIdo Barnea		return err;
982a551c94aSIdo Barnea	}
983a551c94aSIdo Barnea
984a551c94aSIdo Barnea	/* Filter not found, create it. */
985a551c94aSIdo Barnea	DEBUG("%p: filter not found for update, creating new filter",
986a551c94aSIdo Barnea	      (void *)priv);
987a551c94aSIdo Barnea	return priv_fdir_filter_add(priv, fdir_filter);
988a551c94aSIdo Barnea}
989a551c94aSIdo Barnea
990a551c94aSIdo Barnea/**
991a551c94aSIdo Barnea * Delete specific filter.
992a551c94aSIdo Barnea *
993a551c94aSIdo Barnea * @param priv
994a551c94aSIdo Barnea *   Private structure.
995a551c94aSIdo Barnea * @param fdir_filter
996a551c94aSIdo Barnea *   Filter to be deleted.
997a551c94aSIdo Barnea *
998a551c94aSIdo Barnea * @return
999a551c94aSIdo Barnea *   0 on success, errno value on failure.
1000a551c94aSIdo Barnea */
1001a551c94aSIdo Barneastatic int
1002a551c94aSIdo Barneapriv_fdir_filter_delete(struct priv *priv,
1003a551c94aSIdo Barnea			const struct rte_eth_fdir_filter *fdir_filter)
1004a551c94aSIdo Barnea{
1005a551c94aSIdo Barnea	struct mlx5_fdir_filter *mlx5_fdir_filter;
1006a551c94aSIdo Barnea
1007a551c94aSIdo Barnea	mlx5_fdir_filter = priv_find_filter_in_list(priv, fdir_filter);
1008a551c94aSIdo Barnea	if (mlx5_fdir_filter != NULL) {
1009a551c94aSIdo Barnea		struct ibv_exp_flow *flow = mlx5_fdir_filter->flow;
1010a551c94aSIdo Barnea
1011a551c94aSIdo Barnea		/* Remove element from list. */
1012a551c94aSIdo Barnea		LIST_REMOVE(mlx5_fdir_filter, next);
1013a551c94aSIdo Barnea
1014a551c94aSIdo Barnea		/* Destroy flow handle. */
1015a551c94aSIdo Barnea		if (flow != NULL) {
1016a551c94aSIdo Barnea			claim_zero(ibv_exp_destroy_flow(flow));
1017a551c94aSIdo Barnea			mlx5_fdir_filter->flow = NULL;
1018a551c94aSIdo Barnea		}
1019a551c94aSIdo Barnea
1020a551c94aSIdo Barnea		DEBUG("%p: flow director filter %p deleted",
1021a551c94aSIdo Barnea		      (void *)priv, (void *)mlx5_fdir_filter);
1022a551c94aSIdo Barnea
1023a551c94aSIdo Barnea		/* Delete filter. */
1024a551c94aSIdo Barnea		rte_free(mlx5_fdir_filter);
1025a551c94aSIdo Barnea
1026a551c94aSIdo Barnea		return 0;
1027a551c94aSIdo Barnea	}
1028a551c94aSIdo Barnea
102966937478SHanoh Haim#ifndef TREX_PATCH
1030a551c94aSIdo Barnea	ERROR("%p: flow director delete failed, cannot find filter",
1031a551c94aSIdo Barnea	      (void *)priv);
103266937478SHanoh Haim#endif
103366937478SHanoh Haim	 return ENOENT;
1034a551c94aSIdo Barnea}
1035a551c94aSIdo Barnea
1036a551c94aSIdo Barnea/**
1037a551c94aSIdo Barnea * Get flow director information.
1038a551c94aSIdo Barnea *
1039a551c94aSIdo Barnea * @param priv
1040a551c94aSIdo Barnea *   Private structure.
1041a551c94aSIdo Barnea * @param[out] fdir_info
1042a551c94aSIdo Barnea *   Resulting flow director information.
1043a551c94aSIdo Barnea */
1044a551c94aSIdo Barneastatic void
1045a551c94aSIdo Barneapriv_fdir_info_get(struct priv *priv, struct rte_eth_fdir_info *fdir_info)
1046a551c94aSIdo Barnea{
1047a551c94aSIdo Barnea	struct rte_eth_fdir_masks *mask =
1048a551c94aSIdo Barnea		&priv->dev->data->dev_conf.fdir_conf.mask;
1049a551c94aSIdo Barnea
1050a551c94aSIdo Barnea	fdir_info->mode = priv->dev->data->dev_conf.fdir_conf.mode;
1051a551c94aSIdo Barnea	fdir_info->guarant_spc = 0;
1052a551c94aSIdo Barnea
1053a551c94aSIdo Barnea	rte_memcpy(&fdir_info->mask, mask, sizeof(fdir_info->mask));
1054a551c94aSIdo Barnea
1055a551c94aSIdo Barnea	fdir_info->max_flexpayload = 0;
1056a551c94aSIdo Barnea	fdir_info->flow_types_mask[0] = 0;
1057a551c94aSIdo Barnea
1058a551c94aSIdo Barnea	fdir_info->flex_payload_unit = 0;
1059a551c94aSIdo Barnea	fdir_info->max_flex_payload_segment_num = 0;
1060a551c94aSIdo Barnea	fdir_info->flex_payload_limit = 0;
1061a551c94aSIdo Barnea	memset(&fdir_info->flex_conf, 0, sizeof(fdir_info->flex_conf));
1062a551c94aSIdo Barnea}
1063a551c94aSIdo Barnea
1064a551c94aSIdo Barnea/**
1065a551c94aSIdo Barnea * Deal with flow director operations.
1066a551c94aSIdo Barnea *
1067a551c94aSIdo Barnea * @param priv
1068a551c94aSIdo Barnea *   Pointer to private structure.
1069a551c94aSIdo Barnea * @param filter_op
1070a551c94aSIdo Barnea *   Operation to perform.
1071a551c94aSIdo Barnea * @param arg
1072a551c94aSIdo Barnea *   Pointer to operation-specific structure.
1073a551c94aSIdo Barnea *
1074a551c94aSIdo Barnea * @return
1075a551c94aSIdo Barnea *   0 on success, errno value on failure.
1076a551c94aSIdo Barnea */
1077a551c94aSIdo Barneastatic int
1078a551c94aSIdo Barneapriv_fdir_ctrl_func(struct priv *priv, enum rte_filter_op filter_op, void *arg)
1079a551c94aSIdo Barnea{
1080a551c94aSIdo Barnea	enum rte_fdir_mode fdir_mode =
1081a551c94aSIdo Barnea		priv->dev->data->dev_conf.fdir_conf.mode;
1082a551c94aSIdo Barnea	int ret = 0;
1083a551c94aSIdo Barnea
1084a551c94aSIdo Barnea	if (filter_op == RTE_ETH_FILTER_NOP)
1085a551c94aSIdo Barnea		return 0;
1086a551c94aSIdo Barnea
1087a551c94aSIdo Barnea	if (fdir_mode != RTE_FDIR_MODE_PERFECT &&
1088a551c94aSIdo Barnea	    fdir_mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
1089a551c94aSIdo Barnea		ERROR("%p: flow director mode %d not supported",
1090a551c94aSIdo Barnea		      (void *)priv, fdir_mode);
1091a551c94aSIdo Barnea		return EINVAL;
1092a551c94aSIdo Barnea	}
1093a551c94aSIdo Barnea
1094a551c94aSIdo Barnea	switch (filter_op) {
1095a551c94aSIdo Barnea	case RTE_ETH_FILTER_ADD:
1096a551c94aSIdo Barnea		ret = priv_fdir_filter_add(priv, arg);
1097a551c94aSIdo Barnea		break;
1098a551c94aSIdo Barnea	case RTE_ETH_FILTER_UPDATE:
1099a551c94aSIdo Barnea		ret = priv_fdir_filter_update(priv, arg);
1100a551c94aSIdo Barnea		break;
1101a551c94aSIdo Barnea	case RTE_ETH_FILTER_DELETE:
1102a551c94aSIdo Barnea		ret = priv_fdir_filter_delete(priv, arg);
1103a551c94aSIdo Barnea		break;
1104a551c94aSIdo Barnea	case RTE_ETH_FILTER_FLUSH:
1105a551c94aSIdo Barnea		priv_fdir_filter_flush(priv);
1106a551c94aSIdo Barnea		break;
1107a551c94aSIdo Barnea	case RTE_ETH_FILTER_INFO:
1108a551c94aSIdo Barnea		priv_fdir_info_get(priv, arg);
1109a551c94aSIdo Barnea		break;
1110a551c94aSIdo Barnea	default:
1111a551c94aSIdo Barnea		DEBUG("%p: unknown operation %u", (void *)priv, filter_op);
1112a551c94aSIdo Barnea		ret = EINVAL;
1113a551c94aSIdo Barnea		break;
1114a551c94aSIdo Barnea	}
1115a551c94aSIdo Barnea	return ret;
1116a551c94aSIdo Barnea}
1117a551c94aSIdo Barnea
11189ca4a157SIdo Barneastatic const struct rte_flow_ops mlx5_flow_ops = {
11199ca4a157SIdo Barnea	.validate = mlx5_flow_validate,
11209ca4a157SIdo Barnea	.create = mlx5_flow_create,
11219ca4a157SIdo Barnea	.destroy = mlx5_flow_destroy,
11229ca4a157SIdo Barnea	.flush = mlx5_flow_flush,
11239ca4a157SIdo Barnea	.query = NULL,
11249ca4a157SIdo Barnea};
11259ca4a157SIdo Barnea
1126a551c94aSIdo Barnea/**
1127a551c94aSIdo Barnea * Manage filter operations.
1128a551c94aSIdo Barnea *
1129a551c94aSIdo Barnea * @param dev
1130a551c94aSIdo Barnea *   Pointer to Ethernet device structure.
1131a551c94aSIdo Barnea * @param filter_type
1132a551c94aSIdo Barnea *   Filter type.
1133a551c94aSIdo Barnea * @param filter_op
1134a551c94aSIdo Barnea *   Operation to perform.
1135a551c94aSIdo Barnea * @param arg
1136a551c94aSIdo Barnea *   Pointer to operation-specific structure.
1137a551c94aSIdo Barnea *
1138a551c94aSIdo Barnea * @return
1139a551c94aSIdo Barnea *   0 on success, negative errno value on failure.
1140a551c94aSIdo Barnea */
1141a551c94aSIdo Barneaint
1142a551c94aSIdo Barneamlx5_dev_filter_ctrl(struct rte_eth_dev *dev,
1143a551c94aSIdo Barnea		     enum rte_filter_type filter_type,
1144a551c94aSIdo Barnea		     enum rte_filter_op filter_op,
1145a551c94aSIdo Barnea		     void *arg)
1146a551c94aSIdo Barnea{
1147be13fd96SHanoh Haim	int ret = EINVAL;
1148a551c94aSIdo Barnea	struct priv *priv = dev->data->dev_private;
1149a551c94aSIdo Barnea
1150a551c94aSIdo Barnea	switch (filter_type) {
11519ca4a157SIdo Barnea	case RTE_ETH_FILTER_GENERIC:
11529ca4a157SIdo Barnea		if (filter_op != RTE_ETH_FILTER_GET)
11539ca4a157SIdo Barnea			return -EINVAL;
11549ca4a157SIdo Barnea		*(const void **)arg = &mlx5_flow_ops;
11559ca4a157SIdo Barnea		return 0;
1156a551c94aSIdo Barnea	case RTE_ETH_FILTER_FDIR:
1157a551c94aSIdo Barnea		priv_lock(priv);
1158a551c94aSIdo Barnea		ret = priv_fdir_ctrl_func(priv, filter_op, arg);
1159a551c94aSIdo Barnea		priv_unlock(priv);
1160a551c94aSIdo Barnea		break;
1161a551c94aSIdo Barnea	default:
1162a551c94aSIdo Barnea		ERROR("%p: filter type (%d) not supported",
1163a551c94aSIdo Barnea		      (void *)dev, filter_type);
1164a551c94aSIdo Barnea		break;
1165a551c94aSIdo Barnea	}
1166a551c94aSIdo Barnea
1167be13fd96SHanoh Haim	return -ret;
1168a551c94aSIdo Barnea}
1169