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 [ - + ]: 252 : 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->tx_pkt_prepare = NULL;
316 : 0 : dev->dev_ops = &pmd_ops;
317 : 0 : dev->device = &vdev->device;
318 : :
319 : : /* dev->data */
320 : 0 : dev->data->dev_private = dev_private;
321 : 0 : dev->data->dev_link.link_speed = RTE_ETH_SPEED_NUM_100G;
322 : 0 : dev->data->dev_link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
323 : 0 : dev->data->dev_link.link_autoneg = RTE_ETH_LINK_FIXED;
324 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
325 : 0 : dev->data->mac_addrs = ð_addr;
326 : 0 : dev->data->promiscuous = 1;
327 : 0 : dev->data->numa_node = params->cpu_id;
328 : :
329 : 0 : rte_eth_dev_probing_finish(dev);
330 : :
331 : 0 : return 0;
332 : : }
333 : :
334 : : static int
335 : 0 : get_string(const char *key __rte_unused, const char *value, void *extra_args)
336 : : {
337 [ # # ]: 0 : if (!value || !extra_args)
338 : : return -EINVAL;
339 : :
340 : 0 : *(char **)extra_args = strdup(value);
341 : :
342 [ # # ]: 0 : if (!*(char **)extra_args)
343 : 0 : return -ENOMEM;
344 : :
345 : : return 0;
346 : : }
347 : :
348 : : static int
349 : 0 : get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
350 : : {
351 [ # # ]: 0 : if (!value || !extra_args)
352 : : return -EINVAL;
353 : :
354 : 0 : *(uint32_t *)extra_args = strtoull(value, NULL, 0);
355 : :
356 : 0 : return 0;
357 : : }
358 : :
359 : : static int
360 : 0 : get_uint16(const char *key __rte_unused, const char *value, void *extra_args)
361 : : {
362 [ # # ]: 0 : if (!value || !extra_args)
363 : : return -EINVAL;
364 : :
365 : 0 : *(uint16_t *)extra_args = strtoull(value, NULL, 0);
366 : :
367 : 0 : return 0;
368 : : }
369 : :
370 : : static int
371 : 0 : pmd_parse_args(struct pmd_params *p, const char *params)
372 : : {
373 : : struct rte_kvargs *kvlist;
374 : : int ret = 0;
375 : 0 : char *firmware = NULL;
376 : :
377 : 0 : kvlist = rte_kvargs_parse(params, pmd_valid_args);
378 [ # # ]: 0 : if (kvlist == NULL)
379 : : return -EINVAL;
380 : :
381 : : /* Set default values */
382 : : memset(p, 0, sizeof(*p));
383 [ # # ]: 0 : if (rte_strscpy(p->firmware, SOFTNIC_FIRMWARE,
384 : : sizeof(p->firmware)) < 0) {
385 : 0 : PMD_LOG(WARNING,
386 : : "\"%s\": firmware path should be shorter than %zu",
387 : : SOFTNIC_FIRMWARE, sizeof(p->firmware));
388 : : ret = -EINVAL;
389 : 0 : goto out_free;
390 : : }
391 : 0 : p->cpu_id = SOFTNIC_CPU_ID;
392 : 0 : p->sc = SOFTNIC_SC;
393 : :
394 : : /* Firmware script (optional) */
395 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_FIRMWARE) == 1) {
396 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_FIRMWARE,
397 : : &get_string, &firmware);
398 [ # # ]: 0 : if (ret < 0)
399 : 0 : goto out_free;
400 : :
401 [ # # ]: 0 : if (rte_strscpy(p->firmware, firmware,
402 : : sizeof(p->firmware)) < 0) {
403 : 0 : PMD_LOG(WARNING,
404 : : "\"%s\": "
405 : : "firmware path should be shorter than %zu",
406 : : firmware, sizeof(p->firmware));
407 : 0 : free(firmware);
408 : : ret = -EINVAL;
409 : 0 : goto out_free;
410 : : }
411 : 0 : free(firmware);
412 : : }
413 : : /* Connection listening port (optional) */
414 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_CONN_PORT) == 1) {
415 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_CONN_PORT,
416 : 0 : &get_uint16, &p->conn_port);
417 [ # # ]: 0 : if (ret < 0)
418 : 0 : goto out_free;
419 : : }
420 : :
421 : : /* CPU ID (optional) */
422 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_CPU_ID) == 1) {
423 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_CPU_ID,
424 : 0 : &get_uint32, &p->cpu_id);
425 [ # # ]: 0 : if (ret < 0)
426 : 0 : goto out_free;
427 : : }
428 : :
429 : : /* Service cores (optional) */
430 [ # # ]: 0 : if (rte_kvargs_count(kvlist, PMD_PARAM_SC) == 1) {
431 : 0 : ret = rte_kvargs_process(kvlist, PMD_PARAM_SC,
432 : 0 : &get_uint32, &p->sc);
433 [ # # ]: 0 : if (ret < 0)
434 : 0 : goto out_free;
435 : : }
436 : :
437 : 0 : out_free:
438 : 0 : rte_kvargs_free(kvlist);
439 : 0 : return ret;
440 : : }
441 : :
442 : : static int
443 [ # # ]: 0 : pmd_probe(struct rte_vdev_device *vdev)
444 : : {
445 : : struct pmd_params p;
446 : : const char *params;
447 : : int status = 0;
448 : :
449 : : void *dev_private;
450 : : const char *name = rte_vdev_device_name(vdev);
451 : :
452 : 0 : PMD_LOG(INFO, "Probing device \"%s\"", name);
453 : :
454 : : /* Parse input arguments */
455 : : params = rte_vdev_device_args(vdev);
456 [ # # ]: 0 : if (!params)
457 : : return -EINVAL;
458 : :
459 : 0 : status = pmd_parse_args(&p, params);
460 [ # # ]: 0 : if (status)
461 : : return status;
462 : :
463 [ # # ]: 0 : if (rte_strscpy(p.name, name, sizeof(p.name)) < 0) {
464 : 0 : PMD_LOG(WARNING,
465 : : "\"%s\": device name should be shorter than %zu",
466 : : name, sizeof(p.name));
467 : 0 : return -EINVAL;
468 : : }
469 : :
470 : : /* Allocate and initialize soft ethdev private data */
471 : 0 : dev_private = pmd_init(&p);
472 [ # # ]: 0 : if (dev_private == NULL)
473 : : return -ENOMEM;
474 : :
475 : : /* Register soft ethdev */
476 : 0 : PMD_LOG(INFO, "Creating soft ethdev \"%s\"", p.name);
477 : :
478 : 0 : status = pmd_ethdev_register(vdev, &p, dev_private);
479 [ # # ]: 0 : if (status) {
480 : 0 : pmd_free(dev_private);
481 : 0 : return status;
482 : : }
483 : :
484 : : return 0;
485 : : }
486 : :
487 : : static int
488 : 0 : pmd_remove(struct rte_vdev_device *vdev)
489 : : {
490 : : struct rte_eth_dev *dev = NULL;
491 : :
492 [ # # ]: 0 : if (!vdev)
493 : : return -EINVAL;
494 : :
495 : 0 : PMD_LOG(INFO, "Removing device \"%s\"", rte_vdev_device_name(vdev));
496 : :
497 : : /* Find the ethdev entry */
498 : 0 : dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
499 [ # # ]: 0 : if (dev == NULL)
500 : : return 0; /* port already released */
501 : :
502 : 0 : pmd_dev_close(dev);
503 : 0 : rte_eth_dev_release_port(dev);
504 : :
505 : 0 : return 0;
506 : : }
507 : :
508 : : static struct rte_vdev_driver pmd_softnic_drv = {
509 : : .probe = pmd_probe,
510 : : .remove = pmd_remove,
511 : : };
512 : :
513 : 252 : RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
514 : : RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
515 : : PMD_PARAM_FIRMWARE "=<string> "
516 : : PMD_PARAM_CONN_PORT "=<uint16> "
517 : : PMD_PARAM_CPU_ID "=<uint32> "
518 : : );
519 : :
520 : : RTE_EXPORT_SYMBOL(rte_pmd_softnic_manage)
521 : : int
522 : 0 : rte_pmd_softnic_manage(uint16_t port_id)
523 : : {
524 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[port_id];
525 : : struct pmd_internals *softnic;
526 : :
527 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
528 : : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
529 : : #endif
530 : :
531 : 0 : softnic = dev->data->dev_private;
532 : :
533 : 0 : softnic_conn_poll_for_conn(softnic->conn);
534 : :
535 : 0 : softnic_conn_poll_for_msg(softnic->conn);
536 : :
537 : 0 : return 0;
538 : : }
|