xref: /openbmc/linux/drivers/net/ethernet/intel/iavf/iavf_fdir.c (revision 86aa961bb4619a68077ebeba21c52e9ba0eab43d)
1527691bfSHaiyue Wang // SPDX-License-Identifier: GPL-2.0
2527691bfSHaiyue Wang /* Copyright (c) 2020, Intel Corporation. */
3527691bfSHaiyue Wang 
4527691bfSHaiyue Wang /* flow director ethtool support for iavf */
5527691bfSHaiyue Wang 
6*e383353bSJesse Brandeburg #include <linux/bitfield.h>
7527691bfSHaiyue Wang #include "iavf.h"
8527691bfSHaiyue Wang 
9a6379db8SHaiyue Wang #define GTPU_PORT	2152
10a6379db8SHaiyue Wang #define NAT_T_ESP_PORT	4500
11a6379db8SHaiyue Wang #define PFCP_PORT	8805
12a6379db8SHaiyue Wang 
13e90cbc25SHaiyue Wang static const struct in6_addr ipv6_addr_full_mask = {
14e90cbc25SHaiyue Wang 	.in6_u = {
15e90cbc25SHaiyue Wang 		.u6_addr8 = {
16e90cbc25SHaiyue Wang 			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
17e90cbc25SHaiyue Wang 			0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
18e90cbc25SHaiyue Wang 		}
19e90cbc25SHaiyue Wang 	}
20e90cbc25SHaiyue Wang };
21e90cbc25SHaiyue Wang 
22751969e5SPiotr Gardocki static const struct in6_addr ipv6_addr_zero_mask = {
23751969e5SPiotr Gardocki 	.in6_u = {
24751969e5SPiotr Gardocki 		.u6_addr8 = {
25751969e5SPiotr Gardocki 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26751969e5SPiotr Gardocki 		}
27751969e5SPiotr Gardocki 	}
28751969e5SPiotr Gardocki };
29751969e5SPiotr Gardocki 
30751969e5SPiotr Gardocki /**
31751969e5SPiotr Gardocki  * iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks
32751969e5SPiotr Gardocki  * @adapter: pointer to the VF adapter structure
33751969e5SPiotr Gardocki  * @fltr: Flow Director filter data structure
34751969e5SPiotr Gardocki  *
35751969e5SPiotr Gardocki  * Returns 0 if all masks of packet fields are either full or empty. Returns
36751969e5SPiotr Gardocki  * error on at least one partial mask.
37751969e5SPiotr Gardocki  */
iavf_validate_fdir_fltr_masks(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)38751969e5SPiotr Gardocki int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
39751969e5SPiotr Gardocki 				  struct iavf_fdir_fltr *fltr)
40751969e5SPiotr Gardocki {
41751969e5SPiotr Gardocki 	if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX))
42751969e5SPiotr Gardocki 		goto partial_mask;
43751969e5SPiotr Gardocki 
44751969e5SPiotr Gardocki 	if (fltr->ip_ver == 4) {
45751969e5SPiotr Gardocki 		if (fltr->ip_mask.v4_addrs.src_ip &&
46751969e5SPiotr Gardocki 		    fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX))
47751969e5SPiotr Gardocki 			goto partial_mask;
48751969e5SPiotr Gardocki 
49751969e5SPiotr Gardocki 		if (fltr->ip_mask.v4_addrs.dst_ip &&
50751969e5SPiotr Gardocki 		    fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX))
51751969e5SPiotr Gardocki 			goto partial_mask;
52751969e5SPiotr Gardocki 
53751969e5SPiotr Gardocki 		if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX)
54751969e5SPiotr Gardocki 			goto partial_mask;
55751969e5SPiotr Gardocki 	} else if (fltr->ip_ver == 6) {
56751969e5SPiotr Gardocki 		if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask,
57751969e5SPiotr Gardocki 			   sizeof(struct in6_addr)) &&
58751969e5SPiotr Gardocki 		    memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
59751969e5SPiotr Gardocki 			   sizeof(struct in6_addr)))
60751969e5SPiotr Gardocki 			goto partial_mask;
61751969e5SPiotr Gardocki 
62751969e5SPiotr Gardocki 		if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask,
63751969e5SPiotr Gardocki 			   sizeof(struct in6_addr)) &&
64751969e5SPiotr Gardocki 		    memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
65751969e5SPiotr Gardocki 			   sizeof(struct in6_addr)))
66751969e5SPiotr Gardocki 			goto partial_mask;
67751969e5SPiotr Gardocki 
68751969e5SPiotr Gardocki 		if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX)
69751969e5SPiotr Gardocki 			goto partial_mask;
70751969e5SPiotr Gardocki 	}
71751969e5SPiotr Gardocki 
72751969e5SPiotr Gardocki 	if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX)
73751969e5SPiotr Gardocki 		goto partial_mask;
74751969e5SPiotr Gardocki 
75751969e5SPiotr Gardocki 	if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX))
76751969e5SPiotr Gardocki 		goto partial_mask;
77751969e5SPiotr Gardocki 
78751969e5SPiotr Gardocki 	if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX))
79751969e5SPiotr Gardocki 		goto partial_mask;
80751969e5SPiotr Gardocki 
81751969e5SPiotr Gardocki 	if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX))
82751969e5SPiotr Gardocki 		goto partial_mask;
83751969e5SPiotr Gardocki 
84751969e5SPiotr Gardocki 	if (fltr->ip_mask.l4_header &&
85751969e5SPiotr Gardocki 	    fltr->ip_mask.l4_header != htonl(U32_MAX))
86751969e5SPiotr Gardocki 		goto partial_mask;
87751969e5SPiotr Gardocki 
88751969e5SPiotr Gardocki 	return 0;
89751969e5SPiotr Gardocki 
90751969e5SPiotr Gardocki partial_mask:
91751969e5SPiotr Gardocki 	dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n");
92751969e5SPiotr Gardocki 	return -EOPNOTSUPP;
93751969e5SPiotr Gardocki }
94751969e5SPiotr Gardocki 
95527691bfSHaiyue Wang /**
96a6379db8SHaiyue Wang  * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload
97a6379db8SHaiyue Wang  * @fltr: Flow Director filter data structure
98a6379db8SHaiyue Wang  */
iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr * fltr)99a6379db8SHaiyue Wang static u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr)
100a6379db8SHaiyue Wang {
101a6379db8SHaiyue Wang 	return sizeof(struct ethhdr) +
102a6379db8SHaiyue Wang 	       (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
103a6379db8SHaiyue Wang 	       sizeof(struct udphdr);
104a6379db8SHaiyue Wang }
105a6379db8SHaiyue Wang 
106a6379db8SHaiyue Wang /**
107a6379db8SHaiyue Wang  * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header
108a6379db8SHaiyue Wang  * @fltr: Flow Director filter data structure
109a6379db8SHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
110a6379db8SHaiyue Wang  *
111a6379db8SHaiyue Wang  * Returns 0 if the GTP-U protocol header is set successfully
112a6379db8SHaiyue Wang  */
113a6379db8SHaiyue Wang static int
iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)114a6379db8SHaiyue Wang iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr,
115a6379db8SHaiyue Wang 			struct virtchnl_proto_hdrs *proto_hdrs)
116a6379db8SHaiyue Wang {
117a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
118a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
119a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */
120a6379db8SHaiyue Wang 	u16 adj_offs, hdr_offs;
121a6379db8SHaiyue Wang 	int i;
122a6379db8SHaiyue Wang 
123a6379db8SHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP);
124a6379db8SHaiyue Wang 
125a6379db8SHaiyue Wang 	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
126a6379db8SHaiyue Wang 
127a6379db8SHaiyue Wang 	for (i = 0; i < fltr->flex_cnt; i++) {
128a6379db8SHaiyue Wang #define IAVF_GTPU_HDR_TEID_OFFS0	4
129a6379db8SHaiyue Wang #define IAVF_GTPU_HDR_TEID_OFFS1	6
130a6379db8SHaiyue Wang #define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS	10
1311f70dfc5SHaiyue Wang #define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK		0x00FF /* skip N_PDU */
1321f70dfc5SHaiyue Wang /* PDU Session Container Extension Header (PSC) */
1331f70dfc5SHaiyue Wang #define IAVF_GTPU_PSC_EXTHDR_TYPE			0x85
134a6379db8SHaiyue Wang #define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS		13
1351f70dfc5SHaiyue Wang #define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK			0x3F /* skip Type */
1361f70dfc5SHaiyue Wang #define IAVF_GTPU_EH_QFI_IDX				1
1371f70dfc5SHaiyue Wang 
138a6379db8SHaiyue Wang 		if (fltr->flex_words[i].offset < adj_offs)
139a6379db8SHaiyue Wang 			return -EINVAL;
140a6379db8SHaiyue Wang 
141a6379db8SHaiyue Wang 		hdr_offs = fltr->flex_words[i].offset - adj_offs;
142a6379db8SHaiyue Wang 
143a6379db8SHaiyue Wang 		switch (hdr_offs) {
144a6379db8SHaiyue Wang 		case IAVF_GTPU_HDR_TEID_OFFS0:
145a6379db8SHaiyue Wang 		case IAVF_GTPU_HDR_TEID_OFFS1: {
146a6379db8SHaiyue Wang 			__be16 *pay_word = (__be16 *)ghdr->buffer;
147a6379db8SHaiyue Wang 
148a6379db8SHaiyue Wang 			pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word);
149a6379db8SHaiyue Wang 			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID);
150a6379db8SHaiyue Wang 			}
151a6379db8SHaiyue Wang 			break;
152a6379db8SHaiyue Wang 		case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS:
1531f70dfc5SHaiyue Wang 			if ((fltr->flex_words[i].word &
1541f70dfc5SHaiyue Wang 			     IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) !=
1551f70dfc5SHaiyue Wang 						IAVF_GTPU_PSC_EXTHDR_TYPE)
156a6379db8SHaiyue Wang 				return -EOPNOTSUPP;
157a6379db8SHaiyue Wang 			if (!ehdr)
158a6379db8SHaiyue Wang 				ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
159a6379db8SHaiyue Wang 			VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH);
160a6379db8SHaiyue Wang 			break;
161a6379db8SHaiyue Wang 		case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS:
162a6379db8SHaiyue Wang 			if (!ehdr)
163a6379db8SHaiyue Wang 				return -EINVAL;
1641f70dfc5SHaiyue Wang 			ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] =
1651f70dfc5SHaiyue Wang 					fltr->flex_words[i].word &
1661f70dfc5SHaiyue Wang 						IAVF_GTPU_HDR_PSC_PDU_QFI_MASK;
167a6379db8SHaiyue Wang 			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI);
168a6379db8SHaiyue Wang 			break;
169a6379db8SHaiyue Wang 		default:
170a6379db8SHaiyue Wang 			return -EINVAL;
171a6379db8SHaiyue Wang 		}
172a6379db8SHaiyue Wang 	}
173a6379db8SHaiyue Wang 
174a6379db8SHaiyue Wang 	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
175a6379db8SHaiyue Wang 
176a6379db8SHaiyue Wang 	return 0;
177a6379db8SHaiyue Wang }
178a6379db8SHaiyue Wang 
179a6379db8SHaiyue Wang /**
180a6379db8SHaiyue Wang  * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header
181a6379db8SHaiyue Wang  * @fltr: Flow Director filter data structure
182a6379db8SHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
183a6379db8SHaiyue Wang  *
184a6379db8SHaiyue Wang  * Returns 0 if the PFCP protocol header is set successfully
185a6379db8SHaiyue Wang  */
186a6379db8SHaiyue Wang static int
iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)187a6379db8SHaiyue Wang iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr,
188a6379db8SHaiyue Wang 			struct virtchnl_proto_hdrs *proto_hdrs)
189a6379db8SHaiyue Wang {
190a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
191a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
192a6379db8SHaiyue Wang 	u16 adj_offs, hdr_offs;
193a6379db8SHaiyue Wang 	int i;
194a6379db8SHaiyue Wang 
195a6379db8SHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP);
196a6379db8SHaiyue Wang 
197a6379db8SHaiyue Wang 	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
198a6379db8SHaiyue Wang 
199a6379db8SHaiyue Wang 	for (i = 0; i < fltr->flex_cnt; i++) {
200a6379db8SHaiyue Wang #define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS	0
201a6379db8SHaiyue Wang 		if (fltr->flex_words[i].offset < adj_offs)
202a6379db8SHaiyue Wang 			return -EINVAL;
203a6379db8SHaiyue Wang 
204a6379db8SHaiyue Wang 		hdr_offs = fltr->flex_words[i].offset - adj_offs;
205a6379db8SHaiyue Wang 
206a6379db8SHaiyue Wang 		switch (hdr_offs) {
207a6379db8SHaiyue Wang 		case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS:
208a6379db8SHaiyue Wang 			hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff;
209a6379db8SHaiyue Wang 			VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD);
210a6379db8SHaiyue Wang 			break;
211a6379db8SHaiyue Wang 		default:
212a6379db8SHaiyue Wang 			return -EINVAL;
213a6379db8SHaiyue Wang 		}
214a6379db8SHaiyue Wang 	}
215a6379db8SHaiyue Wang 
216a6379db8SHaiyue Wang 	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
217a6379db8SHaiyue Wang 
218a6379db8SHaiyue Wang 	return 0;
219a6379db8SHaiyue Wang }
220a6379db8SHaiyue Wang 
221a6379db8SHaiyue Wang /**
222a6379db8SHaiyue Wang  * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header
223a6379db8SHaiyue Wang  * @fltr: Flow Director filter data structure
224a6379db8SHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
225a6379db8SHaiyue Wang  *
226a6379db8SHaiyue Wang  * Returns 0 if the NAT-T-ESP protocol header is set successfully
227a6379db8SHaiyue Wang  */
228a6379db8SHaiyue Wang static int
iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)229a6379db8SHaiyue Wang iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr,
230a6379db8SHaiyue Wang 			     struct virtchnl_proto_hdrs *proto_hdrs)
231a6379db8SHaiyue Wang {
232a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
233a6379db8SHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
234a6379db8SHaiyue Wang 	u16 adj_offs, hdr_offs;
235a6379db8SHaiyue Wang 	u32 spi = 0;
236a6379db8SHaiyue Wang 	int i;
237a6379db8SHaiyue Wang 
238a6379db8SHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
239a6379db8SHaiyue Wang 
240a6379db8SHaiyue Wang 	adj_offs = iavf_pkt_udp_no_pay_len(fltr);
241a6379db8SHaiyue Wang 
242a6379db8SHaiyue Wang 	for (i = 0; i < fltr->flex_cnt; i++) {
243a6379db8SHaiyue Wang #define IAVF_NAT_T_ESP_SPI_OFFS0	0
244a6379db8SHaiyue Wang #define IAVF_NAT_T_ESP_SPI_OFFS1	2
245a6379db8SHaiyue Wang 		if (fltr->flex_words[i].offset < adj_offs)
246a6379db8SHaiyue Wang 			return -EINVAL;
247a6379db8SHaiyue Wang 
248a6379db8SHaiyue Wang 		hdr_offs = fltr->flex_words[i].offset - adj_offs;
249a6379db8SHaiyue Wang 
250a6379db8SHaiyue Wang 		switch (hdr_offs) {
251a6379db8SHaiyue Wang 		case IAVF_NAT_T_ESP_SPI_OFFS0:
252a6379db8SHaiyue Wang 			spi |= fltr->flex_words[i].word << 16;
253a6379db8SHaiyue Wang 			break;
254a6379db8SHaiyue Wang 		case IAVF_NAT_T_ESP_SPI_OFFS1:
255a6379db8SHaiyue Wang 			spi |= fltr->flex_words[i].word;
256a6379db8SHaiyue Wang 			break;
257a6379db8SHaiyue Wang 		default:
258a6379db8SHaiyue Wang 			return -EINVAL;
259a6379db8SHaiyue Wang 		}
260a6379db8SHaiyue Wang 	}
261a6379db8SHaiyue Wang 
262a6379db8SHaiyue Wang 	if (!spi)
263a6379db8SHaiyue Wang 		return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */
264a6379db8SHaiyue Wang 
265a6379db8SHaiyue Wang 	*(__be32 *)hdr->buffer = htonl(spi);
266a6379db8SHaiyue Wang 	VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
267a6379db8SHaiyue Wang 
268a6379db8SHaiyue Wang 	uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
269a6379db8SHaiyue Wang 
270a6379db8SHaiyue Wang 	return 0;
271a6379db8SHaiyue Wang }
272a6379db8SHaiyue Wang 
273a6379db8SHaiyue Wang /**
274a6379db8SHaiyue Wang  * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header
275a6379db8SHaiyue Wang  * @fltr: Flow Director filter data structure
276a6379db8SHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
277a6379db8SHaiyue Wang  *
278a6379db8SHaiyue Wang  * Returns 0 if the UDP payload defined protocol header is set successfully
279a6379db8SHaiyue Wang  */
280a6379db8SHaiyue Wang static int
iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)281a6379db8SHaiyue Wang iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr,
282a6379db8SHaiyue Wang 				struct virtchnl_proto_hdrs *proto_hdrs)
283a6379db8SHaiyue Wang {
284a6379db8SHaiyue Wang 	int err;
285a6379db8SHaiyue Wang 
286a6379db8SHaiyue Wang 	switch (ntohs(fltr->ip_data.dst_port)) {
287a6379db8SHaiyue Wang 	case GTPU_PORT:
288a6379db8SHaiyue Wang 		err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs);
289a6379db8SHaiyue Wang 		break;
290a6379db8SHaiyue Wang 	case NAT_T_ESP_PORT:
291a6379db8SHaiyue Wang 		err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs);
292a6379db8SHaiyue Wang 		break;
293a6379db8SHaiyue Wang 	case PFCP_PORT:
294a6379db8SHaiyue Wang 		err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs);
295a6379db8SHaiyue Wang 		break;
296a6379db8SHaiyue Wang 	default:
297a6379db8SHaiyue Wang 		err = -EOPNOTSUPP;
298a6379db8SHaiyue Wang 		break;
299a6379db8SHaiyue Wang 	}
300a6379db8SHaiyue Wang 
301a6379db8SHaiyue Wang 	return err;
302a6379db8SHaiyue Wang }
303a6379db8SHaiyue Wang 
304a6379db8SHaiyue Wang /**
305527691bfSHaiyue Wang  * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header
306527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
307527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
308527691bfSHaiyue Wang  *
309527691bfSHaiyue Wang  * Returns 0 if the IPv4 protocol header is set successfully
310527691bfSHaiyue Wang  */
311527691bfSHaiyue Wang static int
iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)312527691bfSHaiyue Wang iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
313527691bfSHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
314527691bfSHaiyue Wang {
315527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
316527691bfSHaiyue Wang 	struct iphdr *iph = (struct iphdr *)hdr->buffer;
317527691bfSHaiyue Wang 
318527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
319527691bfSHaiyue Wang 
320527691bfSHaiyue Wang 	if (fltr->ip_mask.tos == U8_MAX) {
321527691bfSHaiyue Wang 		iph->tos = fltr->ip_data.tos;
322527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP);
323527691bfSHaiyue Wang 	}
324527691bfSHaiyue Wang 
325527691bfSHaiyue Wang 	if (fltr->ip_mask.proto == U8_MAX) {
326527691bfSHaiyue Wang 		iph->protocol = fltr->ip_data.proto;
327527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT);
328527691bfSHaiyue Wang 	}
329527691bfSHaiyue Wang 
330527691bfSHaiyue Wang 	if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) {
331527691bfSHaiyue Wang 		iph->saddr = fltr->ip_data.v4_addrs.src_ip;
332527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
333527691bfSHaiyue Wang 	}
334527691bfSHaiyue Wang 
335527691bfSHaiyue Wang 	if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) {
336527691bfSHaiyue Wang 		iph->daddr = fltr->ip_data.v4_addrs.dst_ip;
337527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
338527691bfSHaiyue Wang 	}
339527691bfSHaiyue Wang 
340527691bfSHaiyue Wang 	return 0;
341527691bfSHaiyue Wang }
342527691bfSHaiyue Wang 
343527691bfSHaiyue Wang /**
344e90cbc25SHaiyue Wang  * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header
345e90cbc25SHaiyue Wang  * @fltr: Flow Director filter data structure
346e90cbc25SHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
347e90cbc25SHaiyue Wang  *
348e90cbc25SHaiyue Wang  * Returns 0 if the IPv6 protocol header is set successfully
349e90cbc25SHaiyue Wang  */
350e90cbc25SHaiyue Wang static int
iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)351e90cbc25SHaiyue Wang iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
352e90cbc25SHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
353e90cbc25SHaiyue Wang {
354e90cbc25SHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
355e90cbc25SHaiyue Wang 	struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;
356e90cbc25SHaiyue Wang 
357e90cbc25SHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
358e90cbc25SHaiyue Wang 
359e90cbc25SHaiyue Wang 	if (fltr->ip_mask.tclass == U8_MAX) {
360e90cbc25SHaiyue Wang 		iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
361e90cbc25SHaiyue Wang 		iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0;
362e90cbc25SHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
363e90cbc25SHaiyue Wang 	}
364e90cbc25SHaiyue Wang 
365e90cbc25SHaiyue Wang 	if (fltr->ip_mask.proto == U8_MAX) {
366e90cbc25SHaiyue Wang 		iph->nexthdr = fltr->ip_data.proto;
367e90cbc25SHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);
368e90cbc25SHaiyue Wang 	}
369e90cbc25SHaiyue Wang 
370e90cbc25SHaiyue Wang 	if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
371e90cbc25SHaiyue Wang 		    sizeof(struct in6_addr))) {
372e90cbc25SHaiyue Wang 		memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,
373e90cbc25SHaiyue Wang 		       sizeof(struct in6_addr));
374e90cbc25SHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
375e90cbc25SHaiyue Wang 	}
376e90cbc25SHaiyue Wang 
377e90cbc25SHaiyue Wang 	if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
378e90cbc25SHaiyue Wang 		    sizeof(struct in6_addr))) {
379e90cbc25SHaiyue Wang 		memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,
380e90cbc25SHaiyue Wang 		       sizeof(struct in6_addr));
381e90cbc25SHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
382e90cbc25SHaiyue Wang 	}
383e90cbc25SHaiyue Wang 
384e90cbc25SHaiyue Wang 	return 0;
385e90cbc25SHaiyue Wang }
386e90cbc25SHaiyue Wang 
387e90cbc25SHaiyue Wang /**
388527691bfSHaiyue Wang  * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header
389527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
390527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
391527691bfSHaiyue Wang  *
392527691bfSHaiyue Wang  * Returns 0 if the TCP protocol header is set successfully
393527691bfSHaiyue Wang  */
394527691bfSHaiyue Wang static int
iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)395527691bfSHaiyue Wang iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr,
396527691bfSHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
397527691bfSHaiyue Wang {
398527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
399527691bfSHaiyue Wang 	struct tcphdr *tcph = (struct tcphdr *)hdr->buffer;
400527691bfSHaiyue Wang 
401527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
402527691bfSHaiyue Wang 
403527691bfSHaiyue Wang 	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
404527691bfSHaiyue Wang 		tcph->source = fltr->ip_data.src_port;
405527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
406527691bfSHaiyue Wang 	}
407527691bfSHaiyue Wang 
408527691bfSHaiyue Wang 	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
409527691bfSHaiyue Wang 		tcph->dest = fltr->ip_data.dst_port;
410527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
411527691bfSHaiyue Wang 	}
412527691bfSHaiyue Wang 
413527691bfSHaiyue Wang 	return 0;
414527691bfSHaiyue Wang }
415527691bfSHaiyue Wang 
416527691bfSHaiyue Wang /**
417527691bfSHaiyue Wang  * iavf_fill_fdir_udp_hdr - fill the UDP protocol header
418527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
419527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
420527691bfSHaiyue Wang  *
421527691bfSHaiyue Wang  * Returns 0 if the UDP protocol header is set successfully
422527691bfSHaiyue Wang  */
423527691bfSHaiyue Wang static int
iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)424527691bfSHaiyue Wang iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr,
425527691bfSHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
426527691bfSHaiyue Wang {
427527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
428527691bfSHaiyue Wang 	struct udphdr *udph = (struct udphdr *)hdr->buffer;
429527691bfSHaiyue Wang 
430527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
431527691bfSHaiyue Wang 
432527691bfSHaiyue Wang 	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
433527691bfSHaiyue Wang 		udph->source = fltr->ip_data.src_port;
434527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
435527691bfSHaiyue Wang 	}
436527691bfSHaiyue Wang 
437527691bfSHaiyue Wang 	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
438527691bfSHaiyue Wang 		udph->dest = fltr->ip_data.dst_port;
439527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
440527691bfSHaiyue Wang 	}
441527691bfSHaiyue Wang 
442a6379db8SHaiyue Wang 	if (!fltr->flex_cnt)
443527691bfSHaiyue Wang 		return 0;
444a6379db8SHaiyue Wang 
445a6379db8SHaiyue Wang 	return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs);
446527691bfSHaiyue Wang }
447527691bfSHaiyue Wang 
448527691bfSHaiyue Wang /**
449527691bfSHaiyue Wang  * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header
450527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
451527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
452527691bfSHaiyue Wang  *
453527691bfSHaiyue Wang  * Returns 0 if the SCTP protocol header is set successfully
454527691bfSHaiyue Wang  */
455527691bfSHaiyue Wang static int
iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)456527691bfSHaiyue Wang iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr,
457527691bfSHaiyue Wang 			struct virtchnl_proto_hdrs *proto_hdrs)
458527691bfSHaiyue Wang {
459527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
460527691bfSHaiyue Wang 	struct sctphdr *sctph = (struct sctphdr *)hdr->buffer;
461527691bfSHaiyue Wang 
462527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
463527691bfSHaiyue Wang 
464527691bfSHaiyue Wang 	if (fltr->ip_mask.src_port == htons(U16_MAX)) {
465527691bfSHaiyue Wang 		sctph->source = fltr->ip_data.src_port;
466527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
467527691bfSHaiyue Wang 	}
468527691bfSHaiyue Wang 
469527691bfSHaiyue Wang 	if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
470527691bfSHaiyue Wang 		sctph->dest = fltr->ip_data.dst_port;
471527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
472527691bfSHaiyue Wang 	}
473527691bfSHaiyue Wang 
474527691bfSHaiyue Wang 	return 0;
475527691bfSHaiyue Wang }
476527691bfSHaiyue Wang 
477527691bfSHaiyue Wang /**
478527691bfSHaiyue Wang  * iavf_fill_fdir_ah_hdr - fill the AH protocol header
479527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
480527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
481527691bfSHaiyue Wang  *
482527691bfSHaiyue Wang  * Returns 0 if the AH protocol header is set successfully
483527691bfSHaiyue Wang  */
484527691bfSHaiyue Wang static int
iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)485527691bfSHaiyue Wang iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr,
486527691bfSHaiyue Wang 		      struct virtchnl_proto_hdrs *proto_hdrs)
487527691bfSHaiyue Wang {
488527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
489527691bfSHaiyue Wang 	struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer;
490527691bfSHaiyue Wang 
491527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH);
492527691bfSHaiyue Wang 
493527691bfSHaiyue Wang 	if (fltr->ip_mask.spi == htonl(U32_MAX)) {
494527691bfSHaiyue Wang 		ah->spi = fltr->ip_data.spi;
495527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI);
496527691bfSHaiyue Wang 	}
497527691bfSHaiyue Wang 
498527691bfSHaiyue Wang 	return 0;
499527691bfSHaiyue Wang }
500527691bfSHaiyue Wang 
501527691bfSHaiyue Wang /**
502527691bfSHaiyue Wang  * iavf_fill_fdir_esp_hdr - fill the ESP protocol header
503527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
504527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
505527691bfSHaiyue Wang  *
506527691bfSHaiyue Wang  * Returns 0 if the ESP protocol header is set successfully
507527691bfSHaiyue Wang  */
508527691bfSHaiyue Wang static int
iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)509527691bfSHaiyue Wang iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr,
510527691bfSHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
511527691bfSHaiyue Wang {
512527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
513527691bfSHaiyue Wang 	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer;
514527691bfSHaiyue Wang 
515527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
516527691bfSHaiyue Wang 
517527691bfSHaiyue Wang 	if (fltr->ip_mask.spi == htonl(U32_MAX)) {
518527691bfSHaiyue Wang 		esph->spi = fltr->ip_data.spi;
519527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
520527691bfSHaiyue Wang 	}
521527691bfSHaiyue Wang 
522527691bfSHaiyue Wang 	return 0;
523527691bfSHaiyue Wang }
524527691bfSHaiyue Wang 
525527691bfSHaiyue Wang /**
526527691bfSHaiyue Wang  * iavf_fill_fdir_l4_hdr - fill the L4 protocol header
527527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
528527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
529527691bfSHaiyue Wang  *
530527691bfSHaiyue Wang  * Returns 0 if the L4 protocol header is set successfully
531527691bfSHaiyue Wang  */
532527691bfSHaiyue Wang static int
iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)533527691bfSHaiyue Wang iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr,
534527691bfSHaiyue Wang 		      struct virtchnl_proto_hdrs *proto_hdrs)
535527691bfSHaiyue Wang {
536527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr;
537527691bfSHaiyue Wang 	__be32 *l4_4_data;
538527691bfSHaiyue Wang 
539527691bfSHaiyue Wang 	if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */
540527691bfSHaiyue Wang 		return 0;
541527691bfSHaiyue Wang 
542527691bfSHaiyue Wang 	hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
543527691bfSHaiyue Wang 	l4_4_data = (__be32 *)hdr->buffer;
544527691bfSHaiyue Wang 
545527691bfSHaiyue Wang 	/* L2TPv3 over IP with 'Session ID' */
546527691bfSHaiyue Wang 	if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) {
547527691bfSHaiyue Wang 		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3);
548527691bfSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID);
549527691bfSHaiyue Wang 
550527691bfSHaiyue Wang 		*l4_4_data = fltr->ip_data.l4_header;
551527691bfSHaiyue Wang 	} else {
552527691bfSHaiyue Wang 		return -EOPNOTSUPP;
553527691bfSHaiyue Wang 	}
554527691bfSHaiyue Wang 
555527691bfSHaiyue Wang 	return 0;
556527691bfSHaiyue Wang }
557527691bfSHaiyue Wang 
558527691bfSHaiyue Wang /**
559527691bfSHaiyue Wang  * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header
560527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
561527691bfSHaiyue Wang  * @proto_hdrs: Flow Director protocol headers data structure
562527691bfSHaiyue Wang  *
563527691bfSHaiyue Wang  * Returns 0 if the Ethernet protocol header is set successfully
564527691bfSHaiyue Wang  */
565527691bfSHaiyue Wang static int
iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)566527691bfSHaiyue Wang iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr,
567527691bfSHaiyue Wang 		       struct virtchnl_proto_hdrs *proto_hdrs)
568527691bfSHaiyue Wang {
569527691bfSHaiyue Wang 	struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
570a6ccffaaSHaiyue Wang 	struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;
571527691bfSHaiyue Wang 
572527691bfSHaiyue Wang 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);
573527691bfSHaiyue Wang 
574a6ccffaaSHaiyue Wang 	if (fltr->eth_mask.etype == htons(U16_MAX)) {
575a6ccffaaSHaiyue Wang 		if (fltr->eth_data.etype == htons(ETH_P_IP) ||
576a6ccffaaSHaiyue Wang 		    fltr->eth_data.etype == htons(ETH_P_IPV6))
577a6ccffaaSHaiyue Wang 			return -EOPNOTSUPP;
578a6ccffaaSHaiyue Wang 
579a6ccffaaSHaiyue Wang 		ehdr->h_proto = fltr->eth_data.etype;
580a6ccffaaSHaiyue Wang 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);
581a6ccffaaSHaiyue Wang 	}
582a6ccffaaSHaiyue Wang 
583527691bfSHaiyue Wang 	return 0;
584527691bfSHaiyue Wang }
585527691bfSHaiyue Wang 
586527691bfSHaiyue Wang /**
587527691bfSHaiyue Wang  * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message
588527691bfSHaiyue Wang  * @adapter: pointer to the VF adapter structure
589527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
590527691bfSHaiyue Wang  *
591527691bfSHaiyue Wang  * Returns 0 if the add Flow Director virtchnl message is filled successfully
592527691bfSHaiyue Wang  */
iavf_fill_fdir_add_msg(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)593527691bfSHaiyue Wang int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
594527691bfSHaiyue Wang {
595527691bfSHaiyue Wang 	struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg;
596527691bfSHaiyue Wang 	struct virtchnl_proto_hdrs *proto_hdrs;
597527691bfSHaiyue Wang 	int err;
598527691bfSHaiyue Wang 
599527691bfSHaiyue Wang 	proto_hdrs = &vc_msg->rule_cfg.proto_hdrs;
600527691bfSHaiyue Wang 
601527691bfSHaiyue Wang 	err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */
602527691bfSHaiyue Wang 	if (err)
603527691bfSHaiyue Wang 		return err;
604527691bfSHaiyue Wang 
605527691bfSHaiyue Wang 	switch (fltr->flow_type) {
606527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_TCP:
607527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
608527691bfSHaiyue Wang 		      iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
609527691bfSHaiyue Wang 		break;
610527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_UDP:
611527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
612527691bfSHaiyue Wang 		      iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
613527691bfSHaiyue Wang 		break;
614527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_SCTP:
615527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
616527691bfSHaiyue Wang 		      iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
617527691bfSHaiyue Wang 		break;
618527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_AH:
619527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
620527691bfSHaiyue Wang 		      iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
621527691bfSHaiyue Wang 		break;
622527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_ESP:
623527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
624527691bfSHaiyue Wang 		      iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
625527691bfSHaiyue Wang 		break;
626527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_OTHER:
627527691bfSHaiyue Wang 		err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
628527691bfSHaiyue Wang 		      iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
629527691bfSHaiyue Wang 		break;
630e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_TCP:
631e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
632e90cbc25SHaiyue Wang 		      iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
633e90cbc25SHaiyue Wang 		break;
634e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_UDP:
635e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
636e90cbc25SHaiyue Wang 		      iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
637e90cbc25SHaiyue Wang 		break;
638e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_SCTP:
639e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
640e90cbc25SHaiyue Wang 		      iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
641e90cbc25SHaiyue Wang 		break;
642e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_AH:
643e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
644e90cbc25SHaiyue Wang 		      iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
645e90cbc25SHaiyue Wang 		break;
646e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_ESP:
647e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
648e90cbc25SHaiyue Wang 		      iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
649e90cbc25SHaiyue Wang 		break;
650e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_OTHER:
651e90cbc25SHaiyue Wang 		err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
652e90cbc25SHaiyue Wang 		      iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
653e90cbc25SHaiyue Wang 		break;
654a6ccffaaSHaiyue Wang 	case IAVF_FDIR_FLOW_NON_IP_L2:
655a6ccffaaSHaiyue Wang 		break;
656527691bfSHaiyue Wang 	default:
657527691bfSHaiyue Wang 		err = -EINVAL;
658527691bfSHaiyue Wang 		break;
659527691bfSHaiyue Wang 	}
660527691bfSHaiyue Wang 
661527691bfSHaiyue Wang 	if (err)
662527691bfSHaiyue Wang 		return err;
663527691bfSHaiyue Wang 
664527691bfSHaiyue Wang 	vc_msg->vsi_id = adapter->vsi.id;
665527691bfSHaiyue Wang 	vc_msg->rule_cfg.action_set.count = 1;
666527691bfSHaiyue Wang 	vc_msg->rule_cfg.action_set.actions[0].type = fltr->action;
667527691bfSHaiyue Wang 	vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index;
668527691bfSHaiyue Wang 
669527691bfSHaiyue Wang 	return 0;
670527691bfSHaiyue Wang }
671527691bfSHaiyue Wang 
672527691bfSHaiyue Wang /**
673527691bfSHaiyue Wang  * iavf_fdir_flow_proto_name - get the flow protocol name
674527691bfSHaiyue Wang  * @flow_type: Flow Director filter flow type
675527691bfSHaiyue Wang  **/
iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)676527691bfSHaiyue Wang static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)
677527691bfSHaiyue Wang {
678527691bfSHaiyue Wang 	switch (flow_type) {
679527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_TCP:
680e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_TCP:
681527691bfSHaiyue Wang 		return "TCP";
682527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_UDP:
683e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_UDP:
684527691bfSHaiyue Wang 		return "UDP";
685527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_SCTP:
686e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_SCTP:
687527691bfSHaiyue Wang 		return "SCTP";
688527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_AH:
689e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_AH:
690527691bfSHaiyue Wang 		return "AH";
691527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_ESP:
692e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_ESP:
693527691bfSHaiyue Wang 		return "ESP";
694527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_OTHER:
695e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_OTHER:
696527691bfSHaiyue Wang 		return "Other";
697a6ccffaaSHaiyue Wang 	case IAVF_FDIR_FLOW_NON_IP_L2:
698a6ccffaaSHaiyue Wang 		return "Ethernet";
699527691bfSHaiyue Wang 	default:
700527691bfSHaiyue Wang 		return NULL;
701527691bfSHaiyue Wang 	}
702527691bfSHaiyue Wang }
703527691bfSHaiyue Wang 
704527691bfSHaiyue Wang /**
705527691bfSHaiyue Wang  * iavf_print_fdir_fltr
706527691bfSHaiyue Wang  * @adapter: adapter structure
707527691bfSHaiyue Wang  * @fltr: Flow Director filter to print
708527691bfSHaiyue Wang  *
709527691bfSHaiyue Wang  * Print the Flow Director filter
710527691bfSHaiyue Wang  **/
iavf_print_fdir_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)711527691bfSHaiyue Wang void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
712527691bfSHaiyue Wang {
713527691bfSHaiyue Wang 	const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type);
714527691bfSHaiyue Wang 
715527691bfSHaiyue Wang 	if (!proto)
716527691bfSHaiyue Wang 		return;
717527691bfSHaiyue Wang 
718527691bfSHaiyue Wang 	switch (fltr->flow_type) {
719527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_TCP:
720527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_UDP:
721527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_SCTP:
722527691bfSHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n",
723527691bfSHaiyue Wang 			 fltr->loc,
724527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.dst_ip,
725527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.src_ip,
726527691bfSHaiyue Wang 			 proto,
727527691bfSHaiyue Wang 			 ntohs(fltr->ip_data.dst_port),
728527691bfSHaiyue Wang 			 ntohs(fltr->ip_data.src_port));
729527691bfSHaiyue Wang 		break;
730527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_AH:
731527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_ESP:
732527691bfSHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n",
733527691bfSHaiyue Wang 			 fltr->loc,
734527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.dst_ip,
735527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.src_ip,
736527691bfSHaiyue Wang 			 proto,
737527691bfSHaiyue Wang 			 ntohl(fltr->ip_data.spi));
738527691bfSHaiyue Wang 		break;
739527691bfSHaiyue Wang 	case IAVF_FDIR_FLOW_IPV4_OTHER:
740527691bfSHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n",
741527691bfSHaiyue Wang 			 fltr->loc,
742527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.dst_ip,
743527691bfSHaiyue Wang 			 &fltr->ip_data.v4_addrs.src_ip,
744527691bfSHaiyue Wang 			 fltr->ip_data.proto,
745527691bfSHaiyue Wang 			 ntohl(fltr->ip_data.l4_header));
746527691bfSHaiyue Wang 		break;
747e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_TCP:
748e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_UDP:
749e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_SCTP:
750e90cbc25SHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",
751e90cbc25SHaiyue Wang 			 fltr->loc,
752e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.dst_ip,
753e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.src_ip,
754e90cbc25SHaiyue Wang 			 proto,
755e90cbc25SHaiyue Wang 			 ntohs(fltr->ip_data.dst_port),
756e90cbc25SHaiyue Wang 			 ntohs(fltr->ip_data.src_port));
757e90cbc25SHaiyue Wang 		break;
758e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_AH:
759e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_ESP:
760e90cbc25SHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",
761e90cbc25SHaiyue Wang 			 fltr->loc,
762e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.dst_ip,
763e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.src_ip,
764e90cbc25SHaiyue Wang 			 proto,
765e90cbc25SHaiyue Wang 			 ntohl(fltr->ip_data.spi));
766e90cbc25SHaiyue Wang 		break;
767e90cbc25SHaiyue Wang 	case IAVF_FDIR_FLOW_IPV6_OTHER:
768e90cbc25SHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",
769e90cbc25SHaiyue Wang 			 fltr->loc,
770e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.dst_ip,
771e90cbc25SHaiyue Wang 			 &fltr->ip_data.v6_addrs.src_ip,
772e90cbc25SHaiyue Wang 			 fltr->ip_data.proto,
773e90cbc25SHaiyue Wang 			 ntohl(fltr->ip_data.l4_header));
774e90cbc25SHaiyue Wang 		break;
775a6ccffaaSHaiyue Wang 	case IAVF_FDIR_FLOW_NON_IP_L2:
776a6ccffaaSHaiyue Wang 		dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",
777a6ccffaaSHaiyue Wang 			 fltr->loc,
778a6ccffaaSHaiyue Wang 			 ntohs(fltr->eth_data.etype));
779a6ccffaaSHaiyue Wang 		break;
780527691bfSHaiyue Wang 	default:
781527691bfSHaiyue Wang 		break;
782527691bfSHaiyue Wang 	}
783527691bfSHaiyue Wang }
784527691bfSHaiyue Wang 
785527691bfSHaiyue Wang /**
786527691bfSHaiyue Wang  * iavf_fdir_is_dup_fltr - test if filter is already in list
787527691bfSHaiyue Wang  * @adapter: pointer to the VF adapter structure
788527691bfSHaiyue Wang  * @fltr: Flow Director filter data structure
789527691bfSHaiyue Wang  *
790527691bfSHaiyue Wang  * Returns true if the filter is found in the list
791527691bfSHaiyue Wang  */
iavf_fdir_is_dup_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)792527691bfSHaiyue Wang bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
793527691bfSHaiyue Wang {
794527691bfSHaiyue Wang 	struct iavf_fdir_fltr *tmp;
7950fb1d8ebSPiotr Gardocki 	bool ret = false;
796527691bfSHaiyue Wang 
7970fb1d8ebSPiotr Gardocki 	spin_lock_bh(&adapter->fdir_fltr_lock);
798527691bfSHaiyue Wang 	list_for_each_entry(tmp, &adapter->fdir_list_head, list) {
799527691bfSHaiyue Wang 		if (tmp->flow_type != fltr->flow_type)
800527691bfSHaiyue Wang 			continue;
801527691bfSHaiyue Wang 
802a6ccffaaSHaiyue Wang 		if (!memcmp(&tmp->eth_data, &fltr->eth_data,
803a6ccffaaSHaiyue Wang 			    sizeof(fltr->eth_data)) &&
804a6ccffaaSHaiyue Wang 		    !memcmp(&tmp->ip_data, &fltr->ip_data,
805a6379db8SHaiyue Wang 			    sizeof(fltr->ip_data)) &&
806a6379db8SHaiyue Wang 		    !memcmp(&tmp->ext_data, &fltr->ext_data,
8070fb1d8ebSPiotr Gardocki 			    sizeof(fltr->ext_data))) {
8080fb1d8ebSPiotr Gardocki 			ret = true;
8090fb1d8ebSPiotr Gardocki 			break;
810527691bfSHaiyue Wang 		}
8110fb1d8ebSPiotr Gardocki 	}
8120fb1d8ebSPiotr Gardocki 	spin_unlock_bh(&adapter->fdir_fltr_lock);
813527691bfSHaiyue Wang 
8140fb1d8ebSPiotr Gardocki 	return ret;
815527691bfSHaiyue Wang }
816527691bfSHaiyue Wang 
817527691bfSHaiyue Wang /**
818527691bfSHaiyue Wang  * iavf_find_fdir_fltr_by_loc - find filter with location
819527691bfSHaiyue Wang  * @adapter: pointer to the VF adapter structure
820527691bfSHaiyue Wang  * @loc: location to find.
821527691bfSHaiyue Wang  *
822527691bfSHaiyue Wang  * Returns pointer to Flow Director filter if found or null
823527691bfSHaiyue Wang  */
iavf_find_fdir_fltr_by_loc(struct iavf_adapter * adapter,u32 loc)824527691bfSHaiyue Wang struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc)
825527691bfSHaiyue Wang {
826527691bfSHaiyue Wang 	struct iavf_fdir_fltr *rule;
827527691bfSHaiyue Wang 
828527691bfSHaiyue Wang 	list_for_each_entry(rule, &adapter->fdir_list_head, list)
829527691bfSHaiyue Wang 		if (rule->loc == loc)
830527691bfSHaiyue Wang 			return rule;
831527691bfSHaiyue Wang 
832527691bfSHaiyue Wang 	return NULL;
833527691bfSHaiyue Wang }
834527691bfSHaiyue Wang 
835527691bfSHaiyue Wang /**
836527691bfSHaiyue Wang  * iavf_fdir_list_add_fltr - add a new node to the flow director filter list
837527691bfSHaiyue Wang  * @adapter: pointer to the VF adapter structure
838527691bfSHaiyue Wang  * @fltr: filter node to add to structure
839527691bfSHaiyue Wang  */
iavf_fdir_list_add_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)840527691bfSHaiyue Wang void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
841527691bfSHaiyue Wang {
842527691bfSHaiyue Wang 	struct iavf_fdir_fltr *rule, *parent = NULL;
843527691bfSHaiyue Wang 
844527691bfSHaiyue Wang 	list_for_each_entry(rule, &adapter->fdir_list_head, list) {
845527691bfSHaiyue Wang 		if (rule->loc >= fltr->loc)
846527691bfSHaiyue Wang 			break;
847527691bfSHaiyue Wang 		parent = rule;
848527691bfSHaiyue Wang 	}
849527691bfSHaiyue Wang 
850527691bfSHaiyue Wang 	if (parent)
851527691bfSHaiyue Wang 		list_add(&fltr->list, &parent->list);
852527691bfSHaiyue Wang 	else
853527691bfSHaiyue Wang 		list_add(&fltr->list, &adapter->fdir_list_head);
854527691bfSHaiyue Wang }
855