Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2017 Intel Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : :
9 : : #include <ethdev_driver.h>
10 : : #include <ethdev_vdev.h>
11 : : #include <eal_export.h>
12 : : #include <rte_malloc.h>
13 : : #include <bus_vdev_driver.h>
14 : : #include <rte_kvargs.h>
15 : : #include <rte_errno.h>
16 : : #include <rte_ring.h>
17 : :
18 : : #include "rte_eth_softnic.h"
19 : : #include "rte_eth_softnic_internals.h"
20 : :
21 : : #define PMD_PARAM_FIRMWARE "firmware"
22 : : #define PMD_PARAM_CONN_PORT "conn_port"
23 : : #define PMD_PARAM_CPU_ID "cpu_id"
24 : : #define PMD_PARAM_SC "sc"
25 : :
26 : :
27 : : static const char * const pmd_valid_args[] = {
28 : : PMD_PARAM_FIRMWARE,
29 : : PMD_PARAM_CONN_PORT,
30 : : PMD_PARAM_CPU_ID,
31 : : PMD_PARAM_SC,
32 : : NULL
33 : : };
34 : :
35 : : static const char welcome[] =
36 : : "\n"
37 : : "Welcome to Soft NIC!\n"
38 : : "\n";
39 : :
40 : : static const char prompt[] = "softnic> ";
41 : :
42 : : static const struct softnic_conn_params conn_params_default = {
43 : : .welcome = welcome,
44 : : .prompt = prompt,
45 : : .addr = "0.0.0.0",
46 : : .port = 0,
47 : : .buf_size = 1024 * 1024,
48 : : .msg_in_len_max = 1024,
49 : : .msg_out_len_max = 1024 * 1024,
50 : : .msg_handle = softnic_cli_process,
51 : : .msg_handle_arg = NULL,
52 : : };
53 : :
54 [ - + ]: 254 : RTE_LOG_REGISTER_DEFAULT(pmd_softnic_logtype, NOTICE);
55 : : #define RTE_LOGTYPE_PMD_SOFTNIC pmd_softnic_logtype
56 : :
57 : : #define PMD_LOG(level, ...) \
58 : : RTE_LOG_LINE_PREFIX(level, PMD_SOFTNIC, "%s(): ", __func__, __VA_ARGS__)
59 : :
60 : : static int
61 : 0 : pmd_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
62 : : struct rte_eth_dev_info *dev_info)
63 : : {
64 : 0 : dev_info->max_rx_pktlen = UINT32_MAX;
65 : 0 : dev_info->max_rx_queues = UINT16_MAX;
66 : 0 : dev_info->max_tx_queues = UINT16_MAX;
67 : 0 : dev_info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
68 : :
69 : 0 : return 0;
70 : : }
71 : :
72 : : static int
73 : 0 : pmd_dev_configure(struct rte_eth_dev *dev __rte_unused)
74 : : {
75 : 0 : return 0;
76 : : }
77 : :
78 : : static int
79 : 0 : pmd_rx_queue_setup(struct rte_eth_dev *dev,
80 : : uint16_t rx_queue_id,
81 : : uint16_t nb_rx_desc,
82 : : unsigned int socket_id __rte_unused,
83 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
84 : : struct rte_mempool *mb_pool __rte_unused)
85 : : {
86 : : char name[NAME_SIZE];
87 : 0 : struct pmd_internals *p = dev->data->dev_private;
88 : : struct softnic_swq *swq;
89 : :
90 : 0 : struct softnic_swq_params params = {
91 : : .size = nb_rx_desc,
92 : : };
93 : :
94 : 0 : snprintf(name, sizeof(name), "RXQ%u", rx_queue_id);
95 : :
96 : 0 : swq = softnic_swq_create(p,
97 : : name,
98 : : ¶ms);
99 [ # # ]: 0 : if (swq == NULL)
100 : : return -1;
101 : :
102 : 0 : dev->data->rx_queues[rx_queue_id] = swq->r;
103 : 0 : return 0;
104 : : }
105 : :
106 : : static int
107 : 0 : pmd_tx_queue_setup(struct rte_eth_dev *dev,
108 : : uint16_t tx_queue_id,
109 : : uint16_t nb_tx_desc,
110 : : unsigned int socket_id __rte_unused,
111 : : const struct rte_eth_txconf *tx_conf __rte_unused)
112 : : {
113 : : char name[NAME_SIZE];
114 : 0 : struct pmd_internals *p = dev->data->dev_private;
115 : : struct softnic_swq *swq;
116 : :
117 : 0 : struct softnic_swq_params params = {
118 : : .size = nb_tx_desc,
119 : : };
120 : :
121 : 0 : snprintf(name, sizeof(name), "TXQ%u", tx_queue_id);
122 : :
123 : 0 : swq = softnic_swq_create(p,
124 : : name,
125 : : ¶ms);
126 [ # # ]: 0 : if (swq == NULL)
127 : : return -1;
128 : :
129 : 0 : dev->data->tx_queues[tx_queue_id] = swq->r;
130 : 0 : return 0;
131 : : }
132 : :
133 : : static int
134 : 0 : pmd_dev_start(struct rte_eth_dev *dev)
135 : : {
136 : 0 : struct pmd_internals *p = dev->data->dev_private;
137 : : int status;
138 : : uint16_t i;
139 : :
140 : : /* Firmware */
141 : 0 : status = softnic_cli_script_process(p,
142 : 0 : p->params.firmware,
143 : : conn_params_default.msg_in_len_max,
144 : : conn_params_default.msg_out_len_max);
145 [ # # ]: 0 : if (status)
146 : : return status;
147 : :
148 : : /* Link UP */
149 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
150 : :
151 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
152 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
153 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
154 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
155 : :
156 : : return 0;
157 : : }
158 : :
159 : : static int
160 : 0 : pmd_dev_stop(struct rte_eth_dev *dev)
161 : : {
162 : 0 : struct pmd_internals *p = dev->data->dev_private;
163 : : uint16_t i;
164 : :
165 : : /* Link DOWN */
166 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
167 : :
168 : : /* Firmware */
169 : 0 : softnic_pipeline_disable_all(p);
170 : 0 : softnic_pipeline_free(p);
171 : 0 : softnic_softnic_swq_free_keep_rxq_txq(p);
172 : 0 : softnic_mempool_free(p);
173 : :
174 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
175 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
176 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
177 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
178 : :
179 : 0 : return 0;
180 : : }
181 : :
182 : : static void
183 : 0 : pmd_free(struct pmd_internals *p)
184 : : {
185 [ # # ]: 0 : if (p == NULL)
186 : : return;
187 : :
188 [ # # ]: 0 : if (p->params.conn_port)
189 : 0 : softnic_conn_free(p->conn);
190 : :
191 : 0 : softnic_thread_free(p);
192 : 0 : softnic_pipeline_free(p);
193 : 0 : softnic_swq_free(p);
194 : 0 : softnic_mempool_free(p);
195 : :
196 : 0 : rte_free(p);
197 : : }
198 : :
199 : : static int
200 : 0 : pmd_dev_close(struct rte_eth_dev *dev)
201 : : {
202 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
203 : : return 0;
204 : :
205 : 0 : pmd_free(dev->data->dev_private);
206 : 0 : dev->data->dev_private = NULL; /* already freed */
207 : 0 : dev->data->mac_addrs = NULL; /* statically allocated */
208 : 0 : return 0;
209 : : }
210 : :
211 : : static int
212 : 0 : pmd_link_update(struct rte_eth_dev *dev __rte_unused,
213 : : int wait_to_complete __rte_unused)
214 : : {
215 : 0 : return 0;
216 : : }
217 : :
218 : : static const struct eth_dev_ops pmd_ops = {
219 : : .dev_configure = pmd_dev_configure,
220 : : .dev_start = pmd_dev_start,
221 : : .dev_stop = pmd_dev_stop,
222 : : .dev_close = pmd_dev_close,
223 : : .link_update = pmd_link_update,
224 : : .dev_infos_get = pmd_dev_infos_get,
225 : : .rx_queue_setup = pmd_rx_queue_setup,
226 : : .tx_queue_setup = pmd_tx_queue_setup,
227 : : };
228 : :
229 : : static uint16_t
230 : 0 : pmd_rx_pkt_burst(void *rxq,
231 : : struct rte_mbuf **rx_pkts,
232 : : uint16_t nb_pkts)
233 : : {
234 : 0 : return (uint16_t)rte_ring_sc_dequeue_burst(rxq,
235 : : (void **)rx_pkts,
236 : : nb_pkts,
237 : : NULL);
238 : : }
239 : :
240 : : static uint16_t
241 : 0 : pmd_tx_pkt_burst(void *txq,
242 : : struct rte_mbuf **tx_pkts,
243 : : uint16_t nb_pkts)
244 : : {
245 : 0 : return (uint16_t)rte_ring_sp_enqueue_burst(txq,
246 : : (void **)tx_pkts,
247 : : nb_pkts,
248 : : NULL);
249 : : }
250 : :
251 : : static void *
252 : 0 : pmd_init(struct pmd_params *params)
253 : : {
254 : : struct pmd_internals *p;
255 : : int status;
256 : :
257 : 0 : p = rte_zmalloc_socket(params->name,
258 : : sizeof(struct pmd_internals),
259 : : 0,
260 : 0 : params->cpu_id);
261 [ # # ]: 0 : if (p == NULL)
262 : : return NULL;
263 : :
264 : : /* Params */
265 : 0 : memcpy(&p->params, params, sizeof(p->params));
266 : :
267 : : /* Resources */
268 : 0 : softnic_mempool_init(p);
269 : 0 : softnic_swq_init(p);
270 : 0 : softnic_pipeline_init(p);
271 : :
272 : 0 : status = softnic_thread_init(p);
273 [ # # ]: 0 : if (status) {
274 : 0 : rte_free(p);
275 : 0 : return NULL;
276 : : }
277 : :
278 [ # # ]: 0 : if (params->conn_port) {
279 : : struct softnic_conn_params conn_params;
280 : :
281 : : memcpy(&conn_params, &conn_params_default, sizeof(conn_params));
282 : 0 : conn_params.port = p->params.conn_port;
283 : 0 : conn_params.msg_handle_arg = p;
284 : :
285 : 0 : p->conn = softnic_conn_init(&conn_params);
286 [ # # ]: 0 : if (p->conn == NULL) {
287 : 0 : softnic_thread_free(p);
288 : 0 : rte_free(p);
289 : 0 : return NULL;
290 : : }
291 : : }
292 : :
293 : : return p;
294 : : }
295 : :
296 : : static struct rte_ether_addr eth_addr = {
297 : : .addr_bytes = {0},
298 : : };
299 : :
300 : : static int
301 : 0 : pmd_ethdev_register(struct rte_vdev_device *vdev,
302 : : struct pmd_params *params,
303 : : void *dev_private)
304 : : {
305 : : struct rte_eth_dev *dev;
306 : :
307 : : /* Ethdev entry allocation */
308 : 0 : dev = rte_eth_dev_allocate(params->name);
309 [ # # ]: 0 : if (!dev)
310 : : return -ENOMEM;
311 : :
312 : : /* dev */
313 : 0 : dev->rx_pkt_burst = pmd_rx_pkt_burst;
314 : 0 : dev->tx_pkt_burst = pmd_tx_pkt_burst;
315 : 0 : dev->dev_ops = &pmd_ops;
316 : 0 : dev->device = &vdev->device;
317 : :
318 : : /* dev->data */
319 : 0 : dev->data->dev_private = dev_private;
320 : 0 : dev->data->dev_link.link_speed = RTE_ETH_SPEED_NUM_100G;
321 : 0 : dev->data->dev_link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
322 : 0 : dev->data->dev_link.link_autoneg = RTE_ETH_LINK_FIXED;
323 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
324 : 0 : dev->data->mac_addrs = ð_addr;
325 : 0 : dev->data->promiscuous = 1;
326 : 0 : dev->data->numa_node = params->cpu_id;
327 : :
328 : 0 : rte_eth_dev_probing_finish(dev);
329 : :
330 : 0 : return 0;
331 : : }
332 : :
333 : : static int
334 : 0 : get_string(const char *key __rte_unused, const char *value, void *extra_args)
335 : : {
336 [ # # ]: 0 : if (!value || !extra_args)
337 : : return -EINVAL;
338 : :
339 : 0 : *(char **)extra_args = strdup(value);
340 : :
341 [ # # ]: 0 : if (!*(char **)extra_args)
342 : 0 : return -ENOMEM;
343 : :
344 : : return 0;
345 : : }
346 : :
347 : : static int
348 : 0 : get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
349 : : {
350 [ # # ]: 0 : if (!value || !extra_args)
351 : : return -EINVAL;
352 : :
353 : 0 : *(uint32_t *)extra_args = strtoull(value, NULL, 0);
354 : :
355 : 0 : return 0;
356 : : }
357 : :
358 : : static int
359 : 0 : get_uint16(const char *key __rte_unused, const char *value, void *extra_args)
360 : : {
361 [ # # ]: 0 : if (!value || !extra_args)
362 : : return -EINVAL;
363 : :
364 : 0 : *(uint16_t *)extra_args = strtoull(value, NULL, 0);
365 : :
366 : 0 : return 0;
367 : : }
368 : :
369 : : static int
370 : 0 : pmd_parse_args(struct pmd_params *p, const char *params)
371 : : {
372 : : struct rte_kvargs *kvlist;
373 : : int ret = 0;
374 : 0 : char *firmware = NULL;
375 : :
376 : 0 : kvlist = rte_kvargs_parse(params, pmd_valid_args);
377 [ # # ]: 0 : if (kvlist == NULL)
378 : : return -EINVAL;
379 : :
380 : : /* Set default values */
381 : : memset(p, 0, sizeof(*p));
382 [ # # ]: 0 : if (rte_strscpy(p->firmware, SOFTNIC_FIRMWARE,
383 : : sizeof(p->firmware)) < 0) {
384 : 0 : PMD_LOG(WARNING,
385 : : "\"%s\": firmware path should be shorter than %zu",
386 : : SOFTNIC_FIRMWARE, sizeof(p->firmware));
387 : : ret = -EINVAL;
388 : 0 : goto out_free;
389 : : }
390 : 0 : p->cpu_id = SOFTNIC_CPU_ID;
391 : 0 : p->sc = SOFTNIC_SC;
392 : :
393 : : /* Firmware script (optional) */
394 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_FIRMWARE) == 1) {
395 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_FIRMWARE,
396 : : &get_string, &firmware);
397 [ # # ]: 0 : if (ret < 0)
398 : 0 : goto out_free;
399 : :
400 [ # # ]: 0 : if (rte_strscpy(p->firmware, firmware,
401 : : sizeof(p->firmware)) < 0) {
402 : 0 : PMD_LOG(WARNING,
403 : : "\"%s\": "
404 : : "firmware path should be shorter than %zu",
405 : : firmware, sizeof(p->firmware));
406 : 0 : free(firmware);
407 : : ret = -EINVAL;
408 : 0 : goto out_free;
409 : : }
410 : 0 : free(firmware);
411 : : }
412 : : /* Connection listening port (optional) */
413 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_CONN_PORT) == 1) {
414 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_CONN_PORT,
415 : 0 : &get_uint16, &p->conn_port);
416 [ # # ]: 0 : if (ret < 0)
417 : 0 : goto out_free;
418 : : }
419 : :
420 : : /* CPU ID (optional) */
421 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_CPU_ID) == 1) {
422 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_CPU_ID,
423 : 0 : &get_uint32, &p->cpu_id);
424 [ # # ]: 0 : if (ret < 0)
425 : 0 : goto out_free;
426 : : }
427 : :
428 : : /* Service cores (optional) */
429 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_SC) == 1) {
430 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_SC,
431 : 0 : &get_uint32, &p->sc);
432 [ # # ]: 0 : if (ret < 0)
433 : 0 : goto out_free;
434 : : }
435 : :
436 : 0 : out_free:
437 : 0 : rte_kvargs_free(kvlist);
438 : 0 : return ret;
439 : : }
440 : :
441 : : static int
442 [ # # ]: 0 : pmd_probe(struct rte_vdev_device *vdev)
443 : : {
444 : : struct pmd_params p;
445 : : const char *params;
446 : : int status = 0;
447 : :
448 : : void *dev_private;
449 : : const char *name = rte_vdev_device_name(vdev);
450 : :
451 : 0 : PMD_LOG(INFO, "Probing device \"%s\"", name);
452 : :
453 : : /* Parse input arguments */
454 : : params = rte_vdev_device_args(vdev);
455 [ # # ]: 0 : if (!params)
456 : : return -EINVAL;
457 : :
458 : 0 : status = pmd_parse_args(&p, params);
459 [ # # ]: 0 : if (status)
460 : : return status;
461 : :
462 [ # # ]: 0 : if (rte_strscpy(p.name, name, sizeof(p.name)) < 0) {
463 : 0 : PMD_LOG(WARNING,
464 : : "\"%s\": device name should be shorter than %zu",
465 : : name, sizeof(p.name));
466 : 0 : return -EINVAL;
467 : : }
468 : :
469 : : /* Allocate and initialize soft ethdev private data */
470 : 0 : dev_private = pmd_init(&p);
471 [ # # ]: 0 : if (dev_private == NULL)
472 : : return -ENOMEM;
473 : :
474 : : /* Register soft ethdev */
475 : 0 : PMD_LOG(INFO, "Creating soft ethdev \"%s\"", p.name);
476 : :
477 : 0 : status = pmd_ethdev_register(vdev, &p, dev_private);
478 [ # # ]: 0 : if (status) {
479 : 0 : pmd_free(dev_private);
480 : 0 : return status;
481 : : }
482 : :
483 : : return 0;
484 : : }
485 : :
486 : : static int
487 : 0 : pmd_remove(struct rte_vdev_device *vdev)
488 : : {
489 : : struct rte_eth_dev *dev = NULL;
490 : :
491 [ # # ]: 0 : if (!vdev)
492 : : return -EINVAL;
493 : :
494 : 0 : PMD_LOG(INFO, "Removing device \"%s\"", rte_vdev_device_name(vdev));
495 : :
496 : : /* Find the ethdev entry */
497 : 0 : dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
498 [ # # ]: 0 : if (dev == NULL)
499 : : return 0; /* port already released */
500 : :
501 : 0 : pmd_dev_close(dev);
502 : 0 : rte_eth_dev_release_port(dev);
503 : :
504 : 0 : return 0;
505 : : }
506 : :
507 : : static struct rte_vdev_driver pmd_softnic_drv = {
508 : : .probe = pmd_probe,
509 : : .remove = pmd_remove,
510 : : };
511 : :
512 : 254 : RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
513 : : RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
514 : : PMD_PARAM_FIRMWARE "=<string> "
515 : : PMD_PARAM_CONN_PORT "=<uint16> "
516 : : PMD_PARAM_CPU_ID "=<uint32> "
517 : : );
518 : :
519 : : RTE_EXPORT_SYMBOL(rte_pmd_softnic_manage)
520 : : int
521 : 0 : rte_pmd_softnic_manage(uint16_t port_id)
522 : : {
523 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[port_id];
524 : : struct pmd_internals *softnic;
525 : :
526 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
527 : : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
528 : : #endif
529 : :
530 : 0 : softnic = dev->data->dev_private;
531 : :
532 : 0 : softnic_conn_poll_for_conn(softnic->conn);
533 : :
534 : 0 : softnic_conn_poll_for_msg(softnic->conn);
535 : :
536 : 0 : return 0;
537 : : }
|