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 <rte_malloc.h>
12 : : #include <bus_vdev_driver.h>
13 : : #include <rte_kvargs.h>
14 : : #include <rte_errno.h>
15 : : #include <rte_ring.h>
16 : :
17 : : #include "rte_eth_softnic.h"
18 : : #include "rte_eth_softnic_internals.h"
19 : :
20 : : #define PMD_PARAM_FIRMWARE "firmware"
21 : : #define PMD_PARAM_CONN_PORT "conn_port"
22 : : #define PMD_PARAM_CPU_ID "cpu_id"
23 : : #define PMD_PARAM_SC "sc"
24 : :
25 : :
26 : : static const char * const pmd_valid_args[] = {
27 : : PMD_PARAM_FIRMWARE,
28 : : PMD_PARAM_CONN_PORT,
29 : : PMD_PARAM_CPU_ID,
30 : : PMD_PARAM_SC,
31 : : NULL
32 : : };
33 : :
34 : : static const char welcome[] =
35 : : "\n"
36 : : "Welcome to Soft NIC!\n"
37 : : "\n";
38 : :
39 : : static const char prompt[] = "softnic> ";
40 : :
41 : : static const struct softnic_conn_params conn_params_default = {
42 : : .welcome = welcome,
43 : : .prompt = prompt,
44 : : .addr = "0.0.0.0",
45 : : .port = 0,
46 : : .buf_size = 1024 * 1024,
47 : : .msg_in_len_max = 1024,
48 : : .msg_out_len_max = 1024 * 1024,
49 : : .msg_handle = softnic_cli_process,
50 : : .msg_handle_arg = NULL,
51 : : };
52 : :
53 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(pmd_softnic_logtype, NOTICE);
54 : : #define RTE_LOGTYPE_PMD_SOFTNIC pmd_softnic_logtype
55 : :
56 : : #define PMD_LOG(level, ...) \
57 : : RTE_LOG_LINE_PREFIX(level, PMD_SOFTNIC, "%s(): ", __func__, __VA_ARGS__)
58 : :
59 : : static int
60 : 0 : pmd_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
61 : : struct rte_eth_dev_info *dev_info)
62 : : {
63 : 0 : dev_info->max_rx_pktlen = UINT32_MAX;
64 : 0 : dev_info->max_rx_queues = UINT16_MAX;
65 : 0 : dev_info->max_tx_queues = UINT16_MAX;
66 : 0 : dev_info->dev_capa &= ~RTE_ETH_DEV_CAPA_FLOW_RULE_KEEP;
67 : :
68 : 0 : return 0;
69 : : }
70 : :
71 : : static int
72 : 0 : pmd_dev_configure(struct rte_eth_dev *dev __rte_unused)
73 : : {
74 : 0 : return 0;
75 : : }
76 : :
77 : : static int
78 : 0 : pmd_rx_queue_setup(struct rte_eth_dev *dev,
79 : : uint16_t rx_queue_id,
80 : : uint16_t nb_rx_desc,
81 : : unsigned int socket_id __rte_unused,
82 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
83 : : struct rte_mempool *mb_pool __rte_unused)
84 : : {
85 : : char name[NAME_SIZE];
86 : 0 : struct pmd_internals *p = dev->data->dev_private;
87 : : struct softnic_swq *swq;
88 : :
89 : 0 : struct softnic_swq_params params = {
90 : : .size = nb_rx_desc,
91 : : };
92 : :
93 : 0 : snprintf(name, sizeof(name), "RXQ%u", rx_queue_id);
94 : :
95 : 0 : swq = softnic_swq_create(p,
96 : : name,
97 : : ¶ms);
98 [ # # ]: 0 : if (swq == NULL)
99 : : return -1;
100 : :
101 : 0 : dev->data->rx_queues[rx_queue_id] = swq->r;
102 : 0 : return 0;
103 : : }
104 : :
105 : : static int
106 : 0 : pmd_tx_queue_setup(struct rte_eth_dev *dev,
107 : : uint16_t tx_queue_id,
108 : : uint16_t nb_tx_desc,
109 : : unsigned int socket_id __rte_unused,
110 : : const struct rte_eth_txconf *tx_conf __rte_unused)
111 : : {
112 : : char name[NAME_SIZE];
113 : 0 : struct pmd_internals *p = dev->data->dev_private;
114 : : struct softnic_swq *swq;
115 : :
116 : 0 : struct softnic_swq_params params = {
117 : : .size = nb_tx_desc,
118 : : };
119 : :
120 : 0 : snprintf(name, sizeof(name), "TXQ%u", tx_queue_id);
121 : :
122 : 0 : swq = softnic_swq_create(p,
123 : : name,
124 : : ¶ms);
125 [ # # ]: 0 : if (swq == NULL)
126 : : return -1;
127 : :
128 : 0 : dev->data->tx_queues[tx_queue_id] = swq->r;
129 : 0 : return 0;
130 : : }
131 : :
132 : : static int
133 : 0 : pmd_dev_start(struct rte_eth_dev *dev)
134 : : {
135 : 0 : struct pmd_internals *p = dev->data->dev_private;
136 : : int status;
137 : : uint16_t i;
138 : :
139 : : /* Firmware */
140 : 0 : status = softnic_cli_script_process(p,
141 : 0 : p->params.firmware,
142 : : conn_params_default.msg_in_len_max,
143 : : conn_params_default.msg_out_len_max);
144 [ # # ]: 0 : if (status)
145 : : return status;
146 : :
147 : : /* Link UP */
148 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
149 : :
150 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
151 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
152 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
153 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
154 : :
155 : : return 0;
156 : : }
157 : :
158 : : static int
159 : 0 : pmd_dev_stop(struct rte_eth_dev *dev)
160 : : {
161 : 0 : struct pmd_internals *p = dev->data->dev_private;
162 : : uint16_t i;
163 : :
164 : : /* Link DOWN */
165 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
166 : :
167 : : /* Firmware */
168 : 0 : softnic_pipeline_disable_all(p);
169 : 0 : softnic_pipeline_free(p);
170 : 0 : softnic_softnic_swq_free_keep_rxq_txq(p);
171 : 0 : softnic_mempool_free(p);
172 : :
173 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
174 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
175 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
176 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
177 : :
178 : 0 : return 0;
179 : : }
180 : :
181 : : static void
182 : 0 : pmd_free(struct pmd_internals *p)
183 : : {
184 [ # # ]: 0 : if (p == NULL)
185 : : return;
186 : :
187 [ # # ]: 0 : if (p->params.conn_port)
188 : 0 : softnic_conn_free(p->conn);
189 : :
190 : 0 : softnic_thread_free(p);
191 : 0 : softnic_pipeline_free(p);
192 : 0 : softnic_swq_free(p);
193 : 0 : softnic_mempool_free(p);
194 : :
195 : 0 : rte_free(p);
196 : : }
197 : :
198 : : static int
199 : 0 : pmd_dev_close(struct rte_eth_dev *dev)
200 : : {
201 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
202 : : return 0;
203 : :
204 : 0 : pmd_free(dev->data->dev_private);
205 : 0 : dev->data->dev_private = NULL; /* already freed */
206 : 0 : dev->data->mac_addrs = NULL; /* statically allocated */
207 : 0 : return 0;
208 : : }
209 : :
210 : : static int
211 : 0 : pmd_link_update(struct rte_eth_dev *dev __rte_unused,
212 : : int wait_to_complete __rte_unused)
213 : : {
214 : 0 : return 0;
215 : : }
216 : :
217 : : static const struct eth_dev_ops pmd_ops = {
218 : : .dev_configure = pmd_dev_configure,
219 : : .dev_start = pmd_dev_start,
220 : : .dev_stop = pmd_dev_stop,
221 : : .dev_close = pmd_dev_close,
222 : : .link_update = pmd_link_update,
223 : : .dev_infos_get = pmd_dev_infos_get,
224 : : .rx_queue_setup = pmd_rx_queue_setup,
225 : : .tx_queue_setup = pmd_tx_queue_setup,
226 : : };
227 : :
228 : : static uint16_t
229 : 0 : pmd_rx_pkt_burst(void *rxq,
230 : : struct rte_mbuf **rx_pkts,
231 : : uint16_t nb_pkts)
232 : : {
233 : 0 : return (uint16_t)rte_ring_sc_dequeue_burst(rxq,
234 : : (void **)rx_pkts,
235 : : nb_pkts,
236 : : NULL);
237 : : }
238 : :
239 : : static uint16_t
240 : 0 : pmd_tx_pkt_burst(void *txq,
241 : : struct rte_mbuf **tx_pkts,
242 : : uint16_t nb_pkts)
243 : : {
244 : 0 : return (uint16_t)rte_ring_sp_enqueue_burst(txq,
245 : : (void **)tx_pkts,
246 : : nb_pkts,
247 : : NULL);
248 : : }
249 : :
250 : : static void *
251 : 0 : pmd_init(struct pmd_params *params)
252 : : {
253 : : struct pmd_internals *p;
254 : : int status;
255 : :
256 : 0 : p = rte_zmalloc_socket(params->name,
257 : : sizeof(struct pmd_internals),
258 : : 0,
259 : 0 : params->cpu_id);
260 [ # # ]: 0 : if (p == NULL)
261 : : return NULL;
262 : :
263 : : /* Params */
264 : 0 : memcpy(&p->params, params, sizeof(p->params));
265 : :
266 : : /* Resources */
267 : 0 : softnic_mempool_init(p);
268 : 0 : softnic_swq_init(p);
269 : 0 : softnic_pipeline_init(p);
270 : :
271 : 0 : status = softnic_thread_init(p);
272 [ # # ]: 0 : if (status) {
273 : 0 : rte_free(p);
274 : 0 : return NULL;
275 : : }
276 : :
277 [ # # ]: 0 : if (params->conn_port) {
278 : : struct softnic_conn_params conn_params;
279 : :
280 : : memcpy(&conn_params, &conn_params_default, sizeof(conn_params));
281 : 0 : conn_params.port = p->params.conn_port;
282 : 0 : conn_params.msg_handle_arg = p;
283 : :
284 : 0 : p->conn = softnic_conn_init(&conn_params);
285 [ # # ]: 0 : if (p->conn == NULL) {
286 : 0 : softnic_thread_free(p);
287 : 0 : rte_free(p);
288 : 0 : return NULL;
289 : : }
290 : : }
291 : :
292 : : return p;
293 : : }
294 : :
295 : : static struct rte_ether_addr eth_addr = {
296 : : .addr_bytes = {0},
297 : : };
298 : :
299 : : static int
300 : 0 : pmd_ethdev_register(struct rte_vdev_device *vdev,
301 : : struct pmd_params *params,
302 : : void *dev_private)
303 : : {
304 : : struct rte_eth_dev *dev;
305 : :
306 : : /* Ethdev entry allocation */
307 : 0 : dev = rte_eth_dev_allocate(params->name);
308 [ # # ]: 0 : if (!dev)
309 : : return -ENOMEM;
310 : :
311 : : /* dev */
312 : 0 : dev->rx_pkt_burst = pmd_rx_pkt_burst;
313 : 0 : dev->tx_pkt_burst = pmd_tx_pkt_burst;
314 : 0 : dev->tx_pkt_prepare = NULL;
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 : 252 : 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 : : int
520 : 0 : rte_pmd_softnic_manage(uint16_t port_id)
521 : : {
522 : 0 : struct rte_eth_dev *dev = &rte_eth_devices[port_id];
523 : : struct pmd_internals *softnic;
524 : :
525 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
526 : : RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
527 : : #endif
528 : :
529 : 0 : softnic = dev->data->dev_private;
530 : :
531 : 0 : softnic_conn_poll_for_conn(softnic->conn);
532 : :
533 : 0 : softnic_conn_poll_for_msg(softnic->conn);
534 : :
535 : 0 : return 0;
536 : : }
|