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