xref: /dpdk/doc/guides/howto/virtio_user_as_exception_path.rst (revision 99c58d238d4a3d7969c94dac1a087d05e1ed14e3)
1..  SPDX-License-Identifier: BSD-3-Clause
2    Copyright(c) 2016 Intel Corporation.
3
4.. _virtio_user_as_exception_path:
5
6Virtio_user as Exception Path
7=============================
8
9.. note::
10
11   This solution is only applicable to Linux systems.
12
13The virtual device, virtio-user, was originally introduced with the vhost-user
14backend as a high performance solution for IPC (Inter-Process Communication)
15and user space container networking.
16
17Beyond this originally intended use,
18virtio-user can be used in conjunction with the vhost-kernel backend
19as a solution for dealing with exception path packets
20which need to be injected into the Linux kernel for processing there.
21In this regard, virtio-user and vhost in kernel space are an alternative to DPDK KNI
22for transferring packets between a DPDK packet processing application and the kernel stack.
23
24This solution has a number of advantages over alternatives such as KNI:
25
26*   Maintenance
27
28    All kernel modules needed by this solution, vhost and vhost-net (kernel),
29    are upstreamed and extensively used.
30
31*   Features
32
33    vhost-net is designed to be a networking solution, and, as such,
34    has lots of networking related features,
35    such as multi queue support, TSO, multi-segment buffer support, etc.
36
37*   Performance
38
39    Similar to KNI, this solution would use one or more kthreads
40    to send/receive packets to/from user space DPDK applications,
41    which minimises the impact on the polling DPDK threads.
42
43The overview of an application using virtio-user as exception path is shown
44in :numref:`figure_virtio_user_as_exception_path`.
45
46.. _figure_virtio_user_as_exception_path:
47
48.. figure:: img/virtio_user_as_exception_path.*
49
50   Overview of a DPDK app using virtio-user as exception path
51
52
53Example Usage With Testpmd
54---------------------------
55
56.. note::
57
58   These instructions assume that the vhost/vhost-net kernel modules are available
59   and have already been loaded into the running kernel.
60   It also assumes that the DPDK virtio driver has not been disabled in the DPDK build.
61
62To run a simple test of virtio-user as exception path using testpmd:
63
64#. Compile DPDK and bind a NIC to vfio-pci as documented in :ref:`linux_gsg_linux_drivers`.
65
66   This physical NIC is for communicating with the outside world,
67   and serves as a packet source in this example.
68
69#. Run testpmd to forward packets from NIC to kernel,
70   passing in a suitable list of logical cores to run on  (``-l`` parameter),
71   and optionally the PCI address of the physical NIC to use (``-a`` parameter).
72   The virtio-user device for interfacing to the kernel is specified via a ``--vdev`` argument,
73   taking the parameters described below.
74
75   .. code-block:: console
76
77      /path/to/dpdk-testpmd -l <cores> -a <pci BDF> \
78          --vdev=virtio_user0,path=/dev/vhost-net,queues=1,queue_size=1024
79
80   ``path``
81     The path to the kernel vhost-net device.
82
83   ``queue_size``
84     256 by default. To avoid shortage of descriptors, we can increase it to 1024.
85
86   ``queues``
87     Number of virt-queues. Each queue will be served by a kthread.
88
89#. Once testpmd is running, a new network interface - called ``tap0`` by default -
90   will be present on the system.
91   This should be configured with an IP address and then enabled for use:
92
93   .. code-block:: console
94
95      ip addr add 192.168.1.1/24 dev tap0
96      ip link set dev tap0 up
97
98#. To observe packet forwarding through the kernel,
99   a second testpmd instance can be run on the system,
100   taking packets from the kernel using an ``af_packet`` socket on the ``tap0`` interface.
101
102   .. code-block:: console
103
104      /path/to/dpdk-testpmd -l <cores> --vdev=net_af_packet0,iface=tap0 --in-memory --no-pci
105
106   When running this instance,
107   we can use ``--in-memory`` flag to avoid hugepage naming conflicts with the previous instance,
108   and we also use ``--no-pci`` flag to only use the ``af_packet`` interface
109   for all traffic forwarding.
110
111#. Running traffic into the system through the NIC should see that traffic returned back again,
112   having been forwarded through both testpmd instances.
113   This can be confirmed by checking the testpmd statistics on testpmd exit.
114
115For more advanced use of virtio-user with testpmd in this scenario,
116some other more advanced options may also be used.
117For example:
118
119* ``--tx-offloads=0x02c``
120
121  This testpmd option enables Tx offloads for UDP and TCP checksum on transmit,
122  as well as TCP TSO support.
123  The list of the offload flag values can be seen in header
124  `rte_ethdev.h <https://doc.dpdk.org/api/rte__ethdev_8h.html>`_.
125
126* ``--enable-lro``
127
128  This testpmd option is used to negotiate VIRTIO_NET_F_GUEST_TSO4 and
129  VIRTIO_NET_F_GUEST_TSO6 feature so that large packets from the kernel can be
130  transmitted to the DPDK application and further TSOed by physical NIC.
131  If unsupported by the physical NIC, errors may be reported by testpmd with this option.
132
133* Enabling Rx checksum offloads for physical port:
134
135  Within testpmd, you can enable and disable offloads on a per-port basis,
136  rather than enabling them for both ports.
137  For the physical NIC, it may be desirable to enable checksum offload on packet Rx.
138  This may be done as below, if testpmd is run with ``-i`` flag for interactive mode.
139
140   .. code-block:: console
141
142      testpmd> port stop 0
143      testpmd> port config 0 rx_offload tcp_cksum on
144      testpmd> port config 0 rx_offload udp_cksum on
145      testpmd> port start 0
146
147* Multiple queue support
148
149  Better performance may be achieved by using multiple queues,
150  so that multiple kernel threads are handling the traffic on the kernel side.
151  For example, to use 2 queues on both NIC and virtio ports,
152  while also enabling TX offloads and LRO support:
153
154  .. code-block:: console
155
156     /path/to/dpdk-testpmd --vdev=virtio_user0,path=/dev/vhost-net,queues=2,queue_size=1024 -- \
157         -i --tx-offloads=0x002c --enable-lro --txq=2 --rxq=2 --txd=1024 --rxd=1024
158
159
160Creating Virtio-User Ports within an Application
161------------------------------------------------
162
163To use virtio-user ports within an application,
164it is not necessary to explicitly initialize those ports using EAL arguments at startup.
165Instead, one can use the generic EAL API
166`rte_eal_hotplug_add <https://doc.dpdk.org/api/rte__dev_8h.html#ad32e8eebf1f81ef9f290cb296b0c90bb>`_
167function to create a new instance at startup.
168For example, to create a basic virtio-user port, the following code could be used:
169
170.. code-block:: C
171
172   rte_eal_hotplug_add("vdev", "virtio_user0", "path=/dev/vhost-net");
173
174A fuller code example is shown below, where a virtio-user port, and hence kernel netdev,
175is created for each NIC port discovered by DPDK.
176Each virtio-user port is given the MAC address of its matching physical port
177(assuming app was run without vdev args on command line, so all ports auto-discovered are HW ones).
178These new virtio-user netdevs will appear in the kernel port listings
179as ``virtio_user0``, ``virtio_user1``, etc.,
180based on the names passed in as ``iface=`` via the ``portargs`` parameter.
181
182.. code-block:: C
183
184   nb_ports = rte_eth_dev_count_avail();
185
186   /* Create a vhost_user port for each physical port */
187   unsigned port_count = 0;
188   RTE_ETH_FOREACH_DEV(portid) {
189       char portname[32];
190       char portargs[256];
191       struct rte_ether_addr addr = {0};
192
193       /* once we have created a virtio port for each physical port, stop creating more */
194       if (++port_count > nb_ports)
195           break;
196
197       /* get MAC address of physical port to use as MAC of virtio_user port */
198       rte_eth_macaddr_get(portid, &addr);
199
200       /* set the name and arguments */
201       snprintf(portname, sizeof(portname), "virtio_user%u", portid);
202       snprintf(portargs, sizeof(portargs),
203               "path=/dev/vhost-net,queues=1,queue_size=%u,iface=%s,mac=" RTE_ETHER_ADDR_PRT_FMT,
204               RX_RING_SIZE, portname, RTE_ETHER_ADDR_BYTES(&addr));
205
206       /* add the vdev for virtio_user */
207       if (rte_eal_hotplug_add("vdev", portname, portargs) < 0)
208           rte_exit(EXIT_FAILURE, "Cannot create paired port for port %u\n", portid);
209
210   }
211
212Once these virtio-user ports have been created in the loop,
213all ports, both physical and virtual,
214may be initialized and used as normal in the application.
215