net/softnic: add softnic PMD
[dpdk.git] / drivers / net / softnic / rte_eth_softnic.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2017 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <rte_ethdev.h>
39 #include <rte_ethdev_vdev.h>
40 #include <rte_malloc.h>
41 #include <rte_vdev.h>
42 #include <rte_kvargs.h>
43 #include <rte_errno.h>
44 #include <rte_ring.h>
45
46 #include "rte_eth_softnic.h"
47 #include "rte_eth_softnic_internals.h"
48
49 #define DEV_HARD(p)                                     \
50         (&rte_eth_devices[p->hard.port_id])
51
52 #define PMD_PARAM_HARD_NAME                                     "hard_name"
53 #define PMD_PARAM_HARD_TX_QUEUE_ID                      "hard_tx_queue_id"
54
55 static const char *pmd_valid_args[] = {
56         PMD_PARAM_HARD_NAME,
57         PMD_PARAM_HARD_TX_QUEUE_ID,
58         NULL
59 };
60
61 static const struct rte_eth_dev_info pmd_dev_info = {
62         .min_rx_bufsize = 0,
63         .max_rx_pktlen = UINT32_MAX,
64         .max_rx_queues = UINT16_MAX,
65         .max_tx_queues = UINT16_MAX,
66         .rx_desc_lim = {
67                 .nb_max = UINT16_MAX,
68                 .nb_min = 0,
69                 .nb_align = 1,
70         },
71         .tx_desc_lim = {
72                 .nb_max = UINT16_MAX,
73                 .nb_min = 0,
74                 .nb_align = 1,
75         },
76 };
77
78 static void
79 pmd_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
80         struct rte_eth_dev_info *dev_info)
81 {
82         memcpy(dev_info, &pmd_dev_info, sizeof(*dev_info));
83 }
84
85 static int
86 pmd_dev_configure(struct rte_eth_dev *dev)
87 {
88         struct pmd_internals *p = dev->data->dev_private;
89         struct rte_eth_dev *hard_dev = DEV_HARD(p);
90
91         if (dev->data->nb_rx_queues > hard_dev->data->nb_rx_queues)
92                 return -1;
93
94         if (p->params.hard.tx_queue_id >= hard_dev->data->nb_tx_queues)
95                 return -1;
96
97         return 0;
98 }
99
100 static int
101 pmd_rx_queue_setup(struct rte_eth_dev *dev,
102         uint16_t rx_queue_id,
103         uint16_t nb_rx_desc __rte_unused,
104         unsigned int socket_id,
105         const struct rte_eth_rxconf *rx_conf __rte_unused,
106         struct rte_mempool *mb_pool __rte_unused)
107 {
108         struct pmd_internals *p = dev->data->dev_private;
109
110         if (p->params.soft.intrusive == 0) {
111                 struct pmd_rx_queue *rxq;
112
113                 rxq = rte_zmalloc_socket(p->params.soft.name,
114                         sizeof(struct pmd_rx_queue), 0, socket_id);
115                 if (rxq == NULL)
116                         return -ENOMEM;
117
118                 rxq->hard.port_id = p->hard.port_id;
119                 rxq->hard.rx_queue_id = rx_queue_id;
120                 dev->data->rx_queues[rx_queue_id] = rxq;
121         } else {
122                 struct rte_eth_dev *hard_dev = DEV_HARD(p);
123                 void *rxq = hard_dev->data->rx_queues[rx_queue_id];
124
125                 if (rxq == NULL)
126                         return -1;
127
128                 dev->data->rx_queues[rx_queue_id] = rxq;
129         }
130         return 0;
131 }
132
133 static int
134 pmd_tx_queue_setup(struct rte_eth_dev *dev,
135         uint16_t tx_queue_id,
136         uint16_t nb_tx_desc,
137         unsigned int socket_id,
138         const struct rte_eth_txconf *tx_conf __rte_unused)
139 {
140         uint32_t size = RTE_ETH_NAME_MAX_LEN + strlen("_txq") + 4;
141         char name[size];
142         struct rte_ring *r;
143
144         snprintf(name, sizeof(name), "%s_txq%04x",
145                 dev->data->name, tx_queue_id);
146         r = rte_ring_create(name, nb_tx_desc, socket_id,
147                 RING_F_SP_ENQ | RING_F_SC_DEQ);
148         if (r == NULL)
149                 return -1;
150
151         dev->data->tx_queues[tx_queue_id] = r;
152         return 0;
153 }
154
155 static int
156 pmd_dev_start(struct rte_eth_dev *dev)
157 {
158         struct pmd_internals *p = dev->data->dev_private;
159
160         dev->data->dev_link.link_status = ETH_LINK_UP;
161
162         if (p->params.soft.intrusive) {
163                 struct rte_eth_dev *hard_dev = DEV_HARD(p);
164
165                 /* The hard_dev->rx_pkt_burst should be stable by now */
166                 dev->rx_pkt_burst = hard_dev->rx_pkt_burst;
167         }
168
169         return 0;
170 }
171
172 static void
173 pmd_dev_stop(struct rte_eth_dev *dev)
174 {
175         dev->data->dev_link.link_status = ETH_LINK_DOWN;
176 }
177
178 static void
179 pmd_dev_close(struct rte_eth_dev *dev)
180 {
181         uint32_t i;
182
183         /* TX queues */
184         for (i = 0; i < dev->data->nb_tx_queues; i++)
185                 rte_ring_free((struct rte_ring *)dev->data->tx_queues[i]);
186 }
187
188 static int
189 pmd_link_update(struct rte_eth_dev *dev __rte_unused,
190         int wait_to_complete __rte_unused)
191 {
192         return 0;
193 }
194
195 static const struct eth_dev_ops pmd_ops = {
196         .dev_configure = pmd_dev_configure,
197         .dev_start = pmd_dev_start,
198         .dev_stop = pmd_dev_stop,
199         .dev_close = pmd_dev_close,
200         .link_update = pmd_link_update,
201         .dev_infos_get = pmd_dev_infos_get,
202         .rx_queue_setup = pmd_rx_queue_setup,
203         .tx_queue_setup = pmd_tx_queue_setup,
204         .tm_ops_get = NULL,
205 };
206
207 static uint16_t
208 pmd_rx_pkt_burst(void *rxq,
209         struct rte_mbuf **rx_pkts,
210         uint16_t nb_pkts)
211 {
212         struct pmd_rx_queue *rx_queue = rxq;
213
214         return rte_eth_rx_burst(rx_queue->hard.port_id,
215                 rx_queue->hard.rx_queue_id,
216                 rx_pkts,
217                 nb_pkts);
218 }
219
220 static uint16_t
221 pmd_tx_pkt_burst(void *txq,
222         struct rte_mbuf **tx_pkts,
223         uint16_t nb_pkts)
224 {
225         return (uint16_t)rte_ring_enqueue_burst(txq,
226                 (void **)tx_pkts,
227                 nb_pkts,
228                 NULL);
229 }
230
231 static __rte_always_inline int
232 run_default(struct rte_eth_dev *dev)
233 {
234         struct pmd_internals *p = dev->data->dev_private;
235
236         /* Persistent context: Read Only (update not required) */
237         struct rte_mbuf **pkts = p->soft.def.pkts;
238         uint16_t nb_tx_queues = dev->data->nb_tx_queues;
239
240         /* Persistent context: Read - Write (update required) */
241         uint32_t txq_pos = p->soft.def.txq_pos;
242         uint32_t pkts_len = p->soft.def.pkts_len;
243         uint32_t flush_count = p->soft.def.flush_count;
244
245         /* Not part of the persistent context */
246         uint32_t pos;
247         uint16_t i;
248
249         /* Soft device TXQ read, Hard device TXQ write */
250         for (i = 0; i < nb_tx_queues; i++) {
251                 struct rte_ring *txq = dev->data->tx_queues[txq_pos];
252
253                 /* Read soft device TXQ burst to packet enqueue buffer */
254                 pkts_len += rte_ring_sc_dequeue_burst(txq,
255                         (void **)&pkts[pkts_len],
256                         DEFAULT_BURST_SIZE,
257                         NULL);
258
259                 /* Increment soft device TXQ */
260                 txq_pos++;
261                 if (txq_pos >= nb_tx_queues)
262                         txq_pos = 0;
263
264                 /* Hard device TXQ write when complete burst is available */
265                 if (pkts_len >= DEFAULT_BURST_SIZE) {
266                         for (pos = 0; pos < pkts_len; )
267                                 pos += rte_eth_tx_burst(p->hard.port_id,
268                                         p->params.hard.tx_queue_id,
269                                         &pkts[pos],
270                                         (uint16_t)(pkts_len - pos));
271
272                         pkts_len = 0;
273                         flush_count = 0;
274                         break;
275                 }
276         }
277
278         if (flush_count >= FLUSH_COUNT_THRESHOLD) {
279                 for (pos = 0; pos < pkts_len; )
280                         pos += rte_eth_tx_burst(p->hard.port_id,
281                                 p->params.hard.tx_queue_id,
282                                 &pkts[pos],
283                                 (uint16_t)(pkts_len - pos));
284
285                 pkts_len = 0;
286                 flush_count = 0;
287         }
288
289         p->soft.def.txq_pos = txq_pos;
290         p->soft.def.pkts_len = pkts_len;
291         p->soft.def.flush_count = flush_count + 1;
292
293         return 0;
294 }
295
296 int
297 rte_pmd_softnic_run(uint16_t port_id)
298 {
299         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
300
301 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
302         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
303 #endif
304
305         return run_default(dev);
306 }
307
308 static struct ether_addr eth_addr = { .addr_bytes = {0} };
309
310 static uint32_t
311 eth_dev_speed_max_mbps(uint32_t speed_capa)
312 {
313         uint32_t rate_mbps[32] = {
314                 ETH_SPEED_NUM_NONE,
315                 ETH_SPEED_NUM_10M,
316                 ETH_SPEED_NUM_10M,
317                 ETH_SPEED_NUM_100M,
318                 ETH_SPEED_NUM_100M,
319                 ETH_SPEED_NUM_1G,
320                 ETH_SPEED_NUM_2_5G,
321                 ETH_SPEED_NUM_5G,
322                 ETH_SPEED_NUM_10G,
323                 ETH_SPEED_NUM_20G,
324                 ETH_SPEED_NUM_25G,
325                 ETH_SPEED_NUM_40G,
326                 ETH_SPEED_NUM_50G,
327                 ETH_SPEED_NUM_56G,
328                 ETH_SPEED_NUM_100G,
329         };
330
331         uint32_t pos = (speed_capa) ? (31 - __builtin_clz(speed_capa)) : 0;
332         return rate_mbps[pos];
333 }
334
335 static int
336 default_init(struct pmd_internals *p,
337         struct pmd_params *params,
338         int numa_node)
339 {
340         p->soft.def.pkts = rte_zmalloc_socket(params->soft.name,
341                 2 * DEFAULT_BURST_SIZE * sizeof(struct rte_mbuf *),
342                 0,
343                 numa_node);
344
345         if (p->soft.def.pkts == NULL)
346                 return -ENOMEM;
347
348         return 0;
349 }
350
351 static void
352 default_free(struct pmd_internals *p)
353 {
354         rte_free(p->soft.def.pkts);
355 }
356
357 static void *
358 pmd_init(struct pmd_params *params, int numa_node)
359 {
360         struct pmd_internals *p;
361         int status;
362
363         p = rte_zmalloc_socket(params->soft.name,
364                 sizeof(struct pmd_internals),
365                 0,
366                 numa_node);
367         if (p == NULL)
368                 return NULL;
369
370         memcpy(&p->params, params, sizeof(p->params));
371         rte_eth_dev_get_port_by_name(params->hard.name, &p->hard.port_id);
372
373         /* Default */
374         status = default_init(p, params, numa_node);
375         if (status) {
376                 free(p->params.hard.name);
377                 rte_free(p);
378                 return NULL;
379         }
380
381         return p;
382 }
383
384 static void
385 pmd_free(struct pmd_internals *p)
386 {
387         default_free(p);
388
389         free(p->params.hard.name);
390         rte_free(p);
391 }
392
393 static int
394 pmd_ethdev_register(struct rte_vdev_device *vdev,
395         struct pmd_params *params,
396         void *dev_private)
397 {
398         struct rte_eth_dev_info hard_info;
399         struct rte_eth_dev *soft_dev;
400         uint32_t hard_speed;
401         int numa_node;
402         uint16_t hard_port_id;
403
404         rte_eth_dev_get_port_by_name(params->hard.name, &hard_port_id);
405         rte_eth_dev_info_get(hard_port_id, &hard_info);
406         hard_speed = eth_dev_speed_max_mbps(hard_info.speed_capa);
407         numa_node = rte_eth_dev_socket_id(hard_port_id);
408
409         /* Ethdev entry allocation */
410         soft_dev = rte_eth_dev_allocate(params->soft.name);
411         if (!soft_dev)
412                 return -ENOMEM;
413
414         /* dev */
415         soft_dev->rx_pkt_burst = (params->soft.intrusive) ?
416                 NULL : /* set up later */
417                 pmd_rx_pkt_burst;
418         soft_dev->tx_pkt_burst = pmd_tx_pkt_burst;
419         soft_dev->tx_pkt_prepare = NULL;
420         soft_dev->dev_ops = &pmd_ops;
421         soft_dev->device = &vdev->device;
422
423         /* dev->data */
424         soft_dev->data->dev_private = dev_private;
425         soft_dev->data->dev_link.link_speed = hard_speed;
426         soft_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
427         soft_dev->data->dev_link.link_autoneg = ETH_LINK_SPEED_FIXED;
428         soft_dev->data->dev_link.link_status = ETH_LINK_DOWN;
429         soft_dev->data->mac_addrs = &eth_addr;
430         soft_dev->data->promiscuous = 1;
431         soft_dev->data->kdrv = RTE_KDRV_NONE;
432         soft_dev->data->numa_node = numa_node;
433         soft_dev->data->dev_flags = RTE_ETH_DEV_DETACHABLE;
434
435         return 0;
436 }
437
438 static int
439 get_string(const char *key __rte_unused, const char *value, void *extra_args)
440 {
441         if (!value || !extra_args)
442                 return -EINVAL;
443
444         *(char **)extra_args = strdup(value);
445
446         if (!*(char **)extra_args)
447                 return -ENOMEM;
448
449         return 0;
450 }
451
452 static int
453 get_uint32(const char *key __rte_unused, const char *value, void *extra_args)
454 {
455         if (!value || !extra_args)
456                 return -EINVAL;
457
458         *(uint32_t *)extra_args = strtoull(value, NULL, 0);
459
460         return 0;
461 }
462
463 static int
464 pmd_parse_args(struct pmd_params *p, const char *name, const char *params)
465 {
466         struct rte_kvargs *kvlist;
467         int ret;
468
469         kvlist = rte_kvargs_parse(params, pmd_valid_args);
470         if (kvlist == NULL)
471                 return -EINVAL;
472
473         /* Set default values */
474         memset(p, 0, sizeof(*p));
475         p->soft.name = name;
476         p->soft.intrusive = INTRUSIVE;
477         p->hard.tx_queue_id = SOFTNIC_HARD_TX_QUEUE_ID;
478
479         /* HARD: name (mandatory) */
480         if (rte_kvargs_count(kvlist, PMD_PARAM_HARD_NAME) == 1) {
481                 ret = rte_kvargs_process(kvlist, PMD_PARAM_HARD_NAME,
482                         &get_string, &p->hard.name);
483                 if (ret < 0)
484                         goto out_free;
485         } else {
486                 ret = -EINVAL;
487                 goto out_free;
488         }
489
490         /* HARD: tx_queue_id (optional) */
491         if (rte_kvargs_count(kvlist, PMD_PARAM_HARD_TX_QUEUE_ID) == 1) {
492                 ret = rte_kvargs_process(kvlist, PMD_PARAM_HARD_TX_QUEUE_ID,
493                         &get_uint32, &p->hard.tx_queue_id);
494                 if (ret < 0)
495                         goto out_free;
496         }
497
498 out_free:
499         rte_kvargs_free(kvlist);
500         return ret;
501 }
502
503 static int
504 pmd_probe(struct rte_vdev_device *vdev)
505 {
506         struct pmd_params p;
507         const char *params;
508         int status;
509
510         struct rte_eth_dev_info hard_info;
511         uint16_t hard_port_id;
512         int numa_node;
513         void *dev_private;
514
515         RTE_LOG(INFO, PMD,
516                 "Probing device \"%s\"\n",
517                 rte_vdev_device_name(vdev));
518
519         /* Parse input arguments */
520         params = rte_vdev_device_args(vdev);
521         if (!params)
522                 return -EINVAL;
523
524         status = pmd_parse_args(&p, rte_vdev_device_name(vdev), params);
525         if (status)
526                 return status;
527
528         /* Check input arguments */
529         if (rte_eth_dev_get_port_by_name(p.hard.name, &hard_port_id))
530                 return -EINVAL;
531
532         rte_eth_dev_info_get(hard_port_id, &hard_info);
533         numa_node = rte_eth_dev_socket_id(hard_port_id);
534
535         if (p.hard.tx_queue_id >= hard_info.max_tx_queues)
536                 return -EINVAL;
537
538         /* Allocate and initialize soft ethdev private data */
539         dev_private = pmd_init(&p, numa_node);
540         if (dev_private == NULL)
541                 return -ENOMEM;
542
543         /* Register soft ethdev */
544         RTE_LOG(INFO, PMD,
545                 "Creating soft ethdev \"%s\" for hard ethdev \"%s\"\n",
546                 p.soft.name, p.hard.name);
547
548         status = pmd_ethdev_register(vdev, &p, dev_private);
549         if (status) {
550                 pmd_free(dev_private);
551                 return status;
552         }
553
554         return 0;
555 }
556
557 static int
558 pmd_remove(struct rte_vdev_device *vdev)
559 {
560         struct rte_eth_dev *dev = NULL;
561         struct pmd_internals *p;
562
563         if (!vdev)
564                 return -EINVAL;
565
566         RTE_LOG(INFO, PMD, "Removing device \"%s\"\n",
567                 rte_vdev_device_name(vdev));
568
569         /* Find the ethdev entry */
570         dev = rte_eth_dev_allocated(rte_vdev_device_name(vdev));
571         if (dev == NULL)
572                 return -ENODEV;
573         p = dev->data->dev_private;
574
575         /* Free device data structures*/
576         pmd_free(p);
577         rte_free(dev->data);
578         rte_eth_dev_release_port(dev);
579
580         return 0;
581 }
582
583 static struct rte_vdev_driver pmd_softnic_drv = {
584         .probe = pmd_probe,
585         .remove = pmd_remove,
586 };
587
588 RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);
589 RTE_PMD_REGISTER_PARAM_STRING(net_softnic,
590         PMD_PARAM_HARD_NAME "=<string> "
591         PMD_PARAM_HARD_TX_QUEUE_ID "=<int>");