]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/drivers/net/qede/qede_fdir.c
update download target update for octopus release
[ceph.git] / ceph / src / seastar / dpdk / drivers / net / qede / qede_fdir.c
1 /*
2 * Copyright (c) 2017 QLogic Corporation.
3 * All rights reserved.
4 * www.qlogic.com
5 *
6 * See LICENSE.qede_pmd for copyright and licensing details.
7 */
8
9 #include <rte_udp.h>
10 #include <rte_tcp.h>
11 #include <rte_sctp.h>
12 #include <rte_errno.h>
13
14 #include "qede_ethdev.h"
15
16 #define IP_VERSION (0x40)
17 #define IP_HDRLEN (0x5)
18 #define QEDE_FDIR_IP_DEFAULT_VERSION_IHL (IP_VERSION | IP_HDRLEN)
19 #define QEDE_FDIR_TCP_DEFAULT_DATAOFF (0x50)
20 #define QEDE_FDIR_IPV4_DEF_TTL (64)
21
22 /* Sum of length of header types of L2, L3, L4.
23 * L2 : ether_hdr + vlan_hdr + vxlan_hdr
24 * L3 : ipv6_hdr
25 * L4 : tcp_hdr
26 */
27 #define QEDE_MAX_FDIR_PKT_LEN (86)
28
29 #ifndef IPV6_ADDR_LEN
30 #define IPV6_ADDR_LEN (16)
31 #endif
32
33 #define QEDE_VALID_FLOW(flow_type) \
34 ((flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
35 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_UDP || \
36 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_TCP || \
37 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_UDP)
38
39 /* Note: Flowdir support is only partial.
40 * For ex: drop_queue, FDIR masks, flex_conf are not supported.
41 * Parameters like pballoc/status fields are irrelevant here.
42 */
43 int qede_check_fdir_support(struct rte_eth_dev *eth_dev)
44 {
45 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
46 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
47 struct rte_fdir_conf *fdir = &eth_dev->data->dev_conf.fdir_conf;
48
49 /* check FDIR modes */
50 switch (fdir->mode) {
51 case RTE_FDIR_MODE_NONE:
52 qdev->fdir_info.arfs.arfs_enable = false;
53 DP_INFO(edev, "flowdir is disabled\n");
54 break;
55 case RTE_FDIR_MODE_PERFECT:
56 if (edev->num_hwfns > 1) {
57 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
58 qdev->fdir_info.arfs.arfs_enable = false;
59 return -ENOTSUP;
60 }
61 qdev->fdir_info.arfs.arfs_enable = true;
62 DP_INFO(edev, "flowdir is enabled\n");
63 break;
64 case RTE_FDIR_MODE_PERFECT_TUNNEL:
65 case RTE_FDIR_MODE_SIGNATURE:
66 case RTE_FDIR_MODE_PERFECT_MAC_VLAN:
67 DP_ERR(edev, "Unsupported flowdir mode %d\n", fdir->mode);
68 return -ENOTSUP;
69 }
70
71 return 0;
72 }
73
74 void qede_fdir_dealloc_resc(struct rte_eth_dev *eth_dev)
75 {
76 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
77 struct qede_fdir_entry *tmp = NULL;
78
79 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
80 if (tmp) {
81 if (tmp->mz)
82 rte_memzone_free(tmp->mz);
83 SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
84 qede_fdir_entry, list);
85 rte_free(tmp);
86 }
87 }
88 }
89
90 static int
91 qede_config_cmn_fdir_filter(struct rte_eth_dev *eth_dev,
92 struct rte_eth_fdir_filter *fdir_filter,
93 bool add)
94 {
95 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
96 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
97 char mz_name[RTE_MEMZONE_NAMESIZE] = {0};
98 struct qede_fdir_entry *tmp = NULL;
99 struct qede_fdir_entry *fdir = NULL;
100 const struct rte_memzone *mz;
101 struct ecore_hwfn *p_hwfn;
102 enum _ecore_status_t rc;
103 uint16_t pkt_len;
104 void *pkt;
105
106 if (add) {
107 if (qdev->fdir_info.filter_count == QEDE_RFS_MAX_FLTR - 1) {
108 DP_ERR(edev, "Reached max flowdir filter limit\n");
109 return -EINVAL;
110 }
111 fdir = rte_malloc(NULL, sizeof(struct qede_fdir_entry),
112 RTE_CACHE_LINE_SIZE);
113 if (!fdir) {
114 DP_ERR(edev, "Did not allocate memory for fdir\n");
115 return -ENOMEM;
116 }
117 }
118 /* soft_id could have been used as memzone string, but soft_id is
119 * not currently used so it has no significance.
120 */
121 snprintf(mz_name, sizeof(mz_name) - 1, "%lx",
122 (unsigned long)rte_get_timer_cycles());
123 mz = rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
124 SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
125 if (!mz) {
126 DP_ERR(edev, "Failed to allocate memzone for fdir, err = %s\n",
127 rte_strerror(rte_errno));
128 rc = -rte_errno;
129 goto err1;
130 }
131
132 pkt = mz->addr;
133 memset(pkt, 0, QEDE_MAX_FDIR_PKT_LEN);
134 pkt_len = qede_fdir_construct_pkt(eth_dev, fdir_filter, pkt,
135 &qdev->fdir_info.arfs);
136 if (pkt_len == 0) {
137 rc = -EINVAL;
138 goto err2;
139 }
140 DP_INFO(edev, "pkt_len = %u memzone = %s\n", pkt_len, mz_name);
141 if (add) {
142 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
143 if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0) {
144 DP_ERR(edev, "flowdir filter exist\n");
145 rc = -EEXIST;
146 goto err2;
147 }
148 }
149 } else {
150 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
151 if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0)
152 break;
153 }
154 if (!tmp) {
155 DP_ERR(edev, "flowdir filter does not exist\n");
156 rc = -EEXIST;
157 goto err2;
158 }
159 }
160 p_hwfn = ECORE_LEADING_HWFN(edev);
161 if (add) {
162 if (!qdev->fdir_info.arfs.arfs_enable) {
163 /* Force update */
164 eth_dev->data->dev_conf.fdir_conf.mode =
165 RTE_FDIR_MODE_PERFECT;
166 qdev->fdir_info.arfs.arfs_enable = true;
167 DP_INFO(edev, "Force enable flowdir in perfect mode\n");
168 }
169 /* Enable ARFS searcher with updated flow_types */
170 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
171 &qdev->fdir_info.arfs);
172 }
173 /* configure filter with ECORE_SPQ_MODE_EBLOCK */
174 rc = ecore_configure_rfs_ntuple_filter(p_hwfn, p_hwfn->p_arfs_ptt, NULL,
175 (dma_addr_t)mz->phys_addr,
176 pkt_len,
177 fdir_filter->action.rx_queue,
178 0, add);
179 if (rc == ECORE_SUCCESS) {
180 if (add) {
181 fdir->rx_queue = fdir_filter->action.rx_queue;
182 fdir->pkt_len = pkt_len;
183 fdir->mz = mz;
184 SLIST_INSERT_HEAD(&qdev->fdir_info.fdir_list_head,
185 fdir, list);
186 qdev->fdir_info.filter_count++;
187 DP_INFO(edev, "flowdir filter added, count = %d\n",
188 qdev->fdir_info.filter_count);
189 } else {
190 rte_memzone_free(tmp->mz);
191 SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
192 qede_fdir_entry, list);
193 rte_free(tmp); /* the node deleted */
194 rte_memzone_free(mz); /* temp node allocated */
195 qdev->fdir_info.filter_count--;
196 DP_INFO(edev, "Fdir filter deleted, count = %d\n",
197 qdev->fdir_info.filter_count);
198 }
199 } else {
200 DP_ERR(edev, "flowdir filter failed, rc=%d filter_count=%d\n",
201 rc, qdev->fdir_info.filter_count);
202 }
203
204 /* Disable ARFS searcher if there are no more filters */
205 if (qdev->fdir_info.filter_count == 0) {
206 memset(&qdev->fdir_info.arfs, 0,
207 sizeof(struct ecore_arfs_config_params));
208 DP_INFO(edev, "Disabling flowdir\n");
209 qdev->fdir_info.arfs.arfs_enable = false;
210 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
211 &qdev->fdir_info.arfs);
212 }
213 return 0;
214
215 err2:
216 rte_memzone_free(mz);
217 err1:
218 if (add)
219 rte_free(fdir);
220 return rc;
221 }
222
223 static int
224 qede_fdir_filter_add(struct rte_eth_dev *eth_dev,
225 struct rte_eth_fdir_filter *fdir,
226 bool add)
227 {
228 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
229 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
230
231 if (!QEDE_VALID_FLOW(fdir->input.flow_type)) {
232 DP_ERR(edev, "invalid flow_type input\n");
233 return -EINVAL;
234 }
235
236 if (fdir->action.rx_queue >= QEDE_RSS_COUNT(qdev)) {
237 DP_ERR(edev, "invalid queue number %u\n",
238 fdir->action.rx_queue);
239 return -EINVAL;
240 }
241
242 if (fdir->input.flow_ext.is_vf) {
243 DP_ERR(edev, "flowdir is not supported over VF\n");
244 return -EINVAL;
245 }
246
247 return qede_config_cmn_fdir_filter(eth_dev, fdir, add);
248 }
249
250 /* Fills the L3/L4 headers and returns the actual length of flowdir packet */
251 uint16_t
252 qede_fdir_construct_pkt(struct rte_eth_dev *eth_dev,
253 struct rte_eth_fdir_filter *fdir,
254 void *buff,
255 struct ecore_arfs_config_params *params)
256
257 {
258 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
259 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
260 uint16_t *ether_type;
261 uint8_t *raw_pkt;
262 struct rte_eth_fdir_input *input;
263 static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
264 struct ipv4_hdr *ip;
265 struct ipv6_hdr *ip6;
266 struct udp_hdr *udp;
267 struct tcp_hdr *tcp;
268 uint16_t len;
269 static const uint8_t next_proto[] = {
270 [RTE_ETH_FLOW_NONFRAG_IPV4_TCP] = IPPROTO_TCP,
271 [RTE_ETH_FLOW_NONFRAG_IPV4_UDP] = IPPROTO_UDP,
272 [RTE_ETH_FLOW_NONFRAG_IPV6_TCP] = IPPROTO_TCP,
273 [RTE_ETH_FLOW_NONFRAG_IPV6_UDP] = IPPROTO_UDP,
274 };
275 raw_pkt = (uint8_t *)buff;
276 input = &fdir->input;
277 DP_INFO(edev, "flow_type %d\n", input->flow_type);
278
279 len = 2 * sizeof(struct ether_addr);
280 raw_pkt += 2 * sizeof(struct ether_addr);
281 if (input->flow_ext.vlan_tci) {
282 DP_INFO(edev, "adding VLAN header\n");
283 rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
284 rte_memcpy(raw_pkt + sizeof(uint16_t),
285 &input->flow_ext.vlan_tci,
286 sizeof(uint16_t));
287 raw_pkt += sizeof(vlan_frame);
288 len += sizeof(vlan_frame);
289 }
290 ether_type = (uint16_t *)raw_pkt;
291 raw_pkt += sizeof(uint16_t);
292 len += sizeof(uint16_t);
293
294 switch (input->flow_type) {
295 case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
296 case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
297 /* fill the common ip header */
298 ip = (struct ipv4_hdr *)raw_pkt;
299 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
300 ip->version_ihl = QEDE_FDIR_IP_DEFAULT_VERSION_IHL;
301 ip->total_length = sizeof(struct ipv4_hdr);
302 ip->next_proto_id = input->flow.ip4_flow.proto ?
303 input->flow.ip4_flow.proto :
304 next_proto[input->flow_type];
305 ip->time_to_live = input->flow.ip4_flow.ttl ?
306 input->flow.ip4_flow.ttl :
307 QEDE_FDIR_IPV4_DEF_TTL;
308 ip->type_of_service = input->flow.ip4_flow.tos;
309 ip->dst_addr = input->flow.ip4_flow.dst_ip;
310 ip->src_addr = input->flow.ip4_flow.src_ip;
311 len += sizeof(struct ipv4_hdr);
312 params->ipv4 = true;
313
314 raw_pkt = (uint8_t *)buff;
315 /* UDP */
316 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
317 udp = (struct udp_hdr *)(raw_pkt + len);
318 udp->dst_port = input->flow.udp4_flow.dst_port;
319 udp->src_port = input->flow.udp4_flow.src_port;
320 udp->dgram_len = sizeof(struct udp_hdr);
321 len += sizeof(struct udp_hdr);
322 /* adjust ip total_length */
323 ip->total_length += sizeof(struct udp_hdr);
324 params->udp = true;
325 } else { /* TCP */
326 tcp = (struct tcp_hdr *)(raw_pkt + len);
327 tcp->src_port = input->flow.tcp4_flow.src_port;
328 tcp->dst_port = input->flow.tcp4_flow.dst_port;
329 tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
330 len += sizeof(struct tcp_hdr);
331 /* adjust ip total_length */
332 ip->total_length += sizeof(struct tcp_hdr);
333 params->tcp = true;
334 }
335 break;
336 case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
337 case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
338 ip6 = (struct ipv6_hdr *)raw_pkt;
339 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
340 ip6->proto = input->flow.ipv6_flow.proto ?
341 input->flow.ipv6_flow.proto :
342 next_proto[input->flow_type];
343 rte_memcpy(&ip6->src_addr, &input->flow.ipv6_flow.dst_ip,
344 IPV6_ADDR_LEN);
345 rte_memcpy(&ip6->dst_addr, &input->flow.ipv6_flow.src_ip,
346 IPV6_ADDR_LEN);
347 len += sizeof(struct ipv6_hdr);
348
349 raw_pkt = (uint8_t *)buff;
350 /* UDP */
351 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP) {
352 udp = (struct udp_hdr *)(raw_pkt + len);
353 udp->src_port = input->flow.udp6_flow.dst_port;
354 udp->dst_port = input->flow.udp6_flow.src_port;
355 len += sizeof(struct udp_hdr);
356 params->udp = true;
357 } else { /* TCP */
358 tcp = (struct tcp_hdr *)(raw_pkt + len);
359 tcp->src_port = input->flow.tcp4_flow.src_port;
360 tcp->dst_port = input->flow.tcp4_flow.dst_port;
361 tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
362 len += sizeof(struct tcp_hdr);
363 params->tcp = true;
364 }
365 break;
366 default:
367 DP_ERR(edev, "Unsupported flow_type %u\n",
368 input->flow_type);
369 return 0;
370 }
371
372 return len;
373 }
374
375 int
376 qede_fdir_filter_conf(struct rte_eth_dev *eth_dev,
377 enum rte_filter_op filter_op,
378 void *arg)
379 {
380 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
381 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
382 struct rte_eth_fdir_filter *fdir;
383 int ret;
384
385 fdir = (struct rte_eth_fdir_filter *)arg;
386 switch (filter_op) {
387 case RTE_ETH_FILTER_NOP:
388 /* Typically used to query flowdir support */
389 if (edev->num_hwfns > 1) {
390 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
391 return -ENOTSUP;
392 }
393 return 0; /* means supported */
394 case RTE_ETH_FILTER_ADD:
395 ret = qede_fdir_filter_add(eth_dev, fdir, 1);
396 break;
397 case RTE_ETH_FILTER_DELETE:
398 ret = qede_fdir_filter_add(eth_dev, fdir, 0);
399 break;
400 case RTE_ETH_FILTER_FLUSH:
401 case RTE_ETH_FILTER_UPDATE:
402 case RTE_ETH_FILTER_INFO:
403 return -ENOTSUP;
404 break;
405 default:
406 DP_ERR(edev, "unknown operation %u", filter_op);
407 ret = -EINVAL;
408 }
409
410 return ret;
411 }
412
413 int qede_ntuple_filter_conf(struct rte_eth_dev *eth_dev,
414 enum rte_filter_op filter_op,
415 void *arg)
416 {
417 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
418 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
419 struct rte_eth_ntuple_filter *ntuple;
420 struct rte_eth_fdir_filter fdir_entry;
421 struct rte_eth_tcpv4_flow *tcpv4_flow;
422 struct rte_eth_udpv4_flow *udpv4_flow;
423 bool add = false;
424
425 switch (filter_op) {
426 case RTE_ETH_FILTER_NOP:
427 /* Typically used to query fdir support */
428 if (edev->num_hwfns > 1) {
429 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
430 return -ENOTSUP;
431 }
432 return 0; /* means supported */
433 case RTE_ETH_FILTER_ADD:
434 add = true;
435 break;
436 case RTE_ETH_FILTER_DELETE:
437 break;
438 case RTE_ETH_FILTER_INFO:
439 case RTE_ETH_FILTER_GET:
440 case RTE_ETH_FILTER_UPDATE:
441 case RTE_ETH_FILTER_FLUSH:
442 case RTE_ETH_FILTER_SET:
443 case RTE_ETH_FILTER_STATS:
444 case RTE_ETH_FILTER_OP_MAX:
445 DP_ERR(edev, "Unsupported filter_op %d\n", filter_op);
446 return -ENOTSUP;
447 }
448 ntuple = (struct rte_eth_ntuple_filter *)arg;
449 /* Internally convert ntuple to fdir entry */
450 memset(&fdir_entry, 0, sizeof(fdir_entry));
451 if (ntuple->proto == IPPROTO_TCP) {
452 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
453 tcpv4_flow = &fdir_entry.input.flow.tcp4_flow;
454 tcpv4_flow->ip.src_ip = ntuple->src_ip;
455 tcpv4_flow->ip.dst_ip = ntuple->dst_ip;
456 tcpv4_flow->ip.proto = IPPROTO_TCP;
457 tcpv4_flow->src_port = ntuple->src_port;
458 tcpv4_flow->dst_port = ntuple->dst_port;
459 } else {
460 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
461 udpv4_flow = &fdir_entry.input.flow.udp4_flow;
462 udpv4_flow->ip.src_ip = ntuple->src_ip;
463 udpv4_flow->ip.dst_ip = ntuple->dst_ip;
464 udpv4_flow->ip.proto = IPPROTO_TCP;
465 udpv4_flow->src_port = ntuple->src_port;
466 udpv4_flow->dst_port = ntuple->dst_port;
467 }
468 return qede_config_cmn_fdir_filter(eth_dev, &fdir_entry, add);
469 }