X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=doc%2Fguides%2Fsample_app_ug%2Fkernel_nic_interface.rst;h=aac4ebd8d4ffe0ef96076478edf02ecd8fca48a9;hb=364b9bfc818641b707b9ab7f04555ff2af1bc3b1;hp=e32fbbf0e5e1973a9ceb644a2f082ca33fcdce7f;hpb=e0c7c47319576799f5affced83caf776ea4de61b;p=dpdk.git diff --git a/doc/guides/sample_app_ug/kernel_nic_interface.rst b/doc/guides/sample_app_ug/kernel_nic_interface.rst index e32fbbf0e5..aac4ebd8d4 100644 --- a/doc/guides/sample_app_ug/kernel_nic_interface.rst +++ b/doc/guides/sample_app_ug/kernel_nic_interface.rst @@ -1,32 +1,5 @@ -.. BSD LICENSE - Copyright(c) 2010-2014 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2010-2014 Intel Corporation. Kernel NIC Interface Sample Application ======================================= @@ -48,274 +21,270 @@ The FIFO queues contain pointers to data packets in the DPDK. This: * Provides a faster mechanism to interface with the kernel net stack and eliminates system calls -* Facilitates the DPDK using standard Linux* userspace net tools (tcpdump, ftp, and so on) +* Facilitates the DPDK using standard Linux* userspace net tools (tshark, rsync, and so on) * Eliminate the copy_to_user and copy_from_user operations on packets. The Kernel NIC Interface sample application is a simple example that demonstrates the use of the DPDK to create a path for packets to go through the Linux* kernel. This is done by creating one or more kernel net devices for each of the DPDK ports. -The application allows the use of standard Linux tools (ethtool, ifconfig, tcpdump) with the DPDK ports and +The application allows the use of standard Linux tools (ethtool, iproute, tshark) with the DPDK ports and also the exchange of packets between the DPDK application and the Linux* kernel. +The Kernel NIC Interface sample application requires that the +KNI kernel module ``rte_kni`` be loaded into the kernel. See +:doc:`../prog_guide/kernel_nic_interface` for more information on loading +the ``rte_kni`` kernel module. + Overview -------- -The Kernel NIC Interface sample application uses two threads in user space for each physical NIC port being used, -and allocates one or more KNI device for each physical NIC port with kernel module's support. -For a physical NIC port, one thread reads from the port and writes to KNI devices, -and another thread reads from KNI devices and writes the data unmodified to the physical NIC port. -It is recommended to configure one KNI device for each physical NIC port. -If configured with more than one KNI devices for a physical NIC port, -it is just for performance testing, or it can work together with VMDq support in future. - -The packet flow through the Kernel NIC Interface application is as shown in the following figure. - -.. _figure_2: - -**Figure 2. Kernel NIC Application Packet Flow** - -.. image3_png has been renamed to kernel_nic.png +The Kernel NIC Interface sample application ``kni`` allocates one or more +KNI interfaces for each physical NIC port. For each physical NIC port, +``kni`` uses two DPDK threads in user space; one thread reads from the port and +writes to the corresponding KNI interfaces and the other thread reads from +the KNI interfaces and writes the data unmodified to the physical NIC port. -|kernel_nic| +It is recommended to configure one KNI interface for each physical NIC port. +The application can be configured with more than one KNI interface for +each physical NIC port for performance testing or it can work together with +VMDq support in future. -Compiling the Application -------------------------- - -Compile the application as follows: +The packet flow through the Kernel NIC Interface application is as shown +in the following figure. -#. Go to the example directory: +.. _figure_kernel_nic: - .. code-block:: console +.. figure:: img/kernel_nic.* - export RTE_SDK=/path/to/rte_sdk cd - ${RTE_SDK}/examples/kni + Kernel NIC Application Packet Flow -#. Set the target (a default target is used if not specified) +If link monitoring is enabled with the ``-m`` command line flag, one +additional pthread is launched which will check the link status of each +physical NIC port and will update the carrier status of the corresponding +KNI interface(s) to match the physical NIC port's state. This means that +the KNI interface(s) will be disabled automatically when the Ethernet link +goes down and enabled when the Ethernet link goes up. - .. note:: +If link monitoring is enabled, the ``rte_kni`` kernel module should be loaded +such that the :ref:`default carrier state ` is +set to *off*. This ensures that the KNI interface is only enabled *after* +the Ethernet link of the corresponding NIC port has reached the linkup state. - This application is intended as a linuxapp only. +If link monitoring is not enabled, the ``rte_kni`` kernel module should be +loaded with the :ref:`default carrier state ` +set to *on*. This sets the carrier state of the KNI interfaces to *on* +when the KNI interfaces are enabled without regard to the actual link state +of the corresponding NIC port. This is useful for testing in loopback +mode where the NIC port may not be physically connected to anything. - .. code-block:: console +Compiling the Application +------------------------- - export RTE_TARGET=x86_64-native-linuxapp-gcc +To compile the sample application see :doc:`compiling`. -#. Build the application: +The application is located in the ``examples/kni`` sub-directory. - .. code-block:: console +.. note:: - make + This application is intended as a linux only. -Loading the Kernel Module -------------------------- +Running the kni Example Application +----------------------------------- -Loading the KNI kernel module without any parameter is the typical way a DPDK application -gets packets into and out of the kernel net stack. -This way, only one kernel thread is created for all KNI devices for packet receiving in kernel side: +The ``kni`` example application requires a number of command line options: .. code-block:: console - #insmod rte_kni.ko + kni [EAL options] -- -p PORTMASK --config="(port,lcore_rx,lcore_tx[,lcore_kthread,...])[,(port,lcore_rx,lcore_tx[,lcore_kthread,...])]" [-P] [-m] -Pinning the kernel thread to a specific core can be done using a taskset command such as following: +Where: -.. code-block:: console +* ``-p PORTMASK``: - #taskset -p 100000 `pgrep --fl kni_thread | awk '{print $1}'` + Hexadecimal bitmask of ports to configure. -This command line tries to pin the specific kni_thread on the 20th lcore (lcore numbering starts at 0), -which means it needs to check if that lcore is available on the board. -This command must be sent after the application has been launched, as insmod does not start the kni thread. +* ``--config="(port,lcore_rx,lcore_tx[,lcore_kthread,...])[,(port,lcore_rx,lcore_tx[,lcore_kthread,...])]"``: -For optimum performance, -the lcore in the mask must be selected to be on the same socket as the lcores used in the KNI application. + Determines which lcores the Rx and Tx DPDK tasks, and (optionally) + the KNI kernel thread(s) are bound to for each physical port. -To provide flexibility of performance, the kernel module of the KNI, -located in the kmod sub-directory of the DPDK target directory, -can be loaded with parameter of kthread_mode as follows: +* ``-P``: -* #insmod rte_kni.ko kthread_mode=single + Optional flag to set all ports to promiscuous mode so that packets are + accepted regardless of the packet's Ethernet MAC destination address. + Without this option, only packets with the Ethernet MAC destination + address set to the Ethernet address of the port are accepted. - This mode will create only one kernel thread for all KNI devices for packet receiving in kernel side. - By default, it is in this single kernel thread mode. - It can set core affinity for this kernel thread by using Linux command taskset. +* ``-m``: -* #insmod rte_kni.ko kthread_mode =multiple + Optional flag to enable monitoring and updating of the Ethernet + carrier state. With this option set, a thread will be started which + will periodically check the Ethernet link status of the physical + Ethernet ports and set the carrier state of the corresponding KNI + network interface to match it. This means that the KNI interface will + be disabled automatically when the Ethernet link goes down and enabled + when the Ethernet link goes up. - This mode will create a kernel thread for each KNI device for packet receiving in kernel side. - The core affinity of each kernel thread is set when creating the KNI device. - The lcore ID for each kernel thread is provided in the command line of launching the application. - Multiple kernel thread mode can provide scalable higher performance. +Refer to *DPDK Getting Started Guide* for general information on running +applications and the Environment Abstraction Layer (EAL) options. -To measure the throughput in a loopback mode, the kernel module of the KNI, -located in the kmod sub-directory of the DPDK target directory, -can be loaded with parameters as follows: +The ``-c coremask`` or ``-l corelist`` parameter of the EAL options must +include the lcores specified by ``lcore_rx`` and ``lcore_tx`` for each port, +but does not need to include lcores specified by ``lcore_kthread`` as those +cores are used to pin the kernel threads in the ``rte_kni`` kernel module. -* #insmod rte_kni.ko lo_mode=lo_mode_fifo +The ``--config`` parameter must include a set of +``(port,lcore_rx,lcore_tx,[lcore_kthread,...])`` values for each physical +port specified in the ``-p PORTMASK`` parameter. - This loopback mode will involve ring enqueue/dequeue operations in kernel space. +The optional ``lcore_kthread`` lcore ID parameter in ``--config`` can be +specified zero, one or more times for each physical port. -* #insmod rte_kni.ko lo_mode=lo_mode_fifo_skb +If no lcore ID is specified for ``lcore_kthread``, one KNI interface will +be created for the physical port ``port`` and the KNI kernel thread(s) +will have no specific core affinity. - This loopback mode will involve ring enqueue/dequeue operations and sk buffer copies in kernel space. +If one or more lcore IDs are specified for ``lcore_kthread``, a KNI interface +will be created for each lcore ID specified, bound to the physical port +``port``. If the ``rte_kni`` kernel module is loaded in :ref:`multiple +kernel thread ` mode, a kernel thread will be created +for each KNI interface and bound to the specified core. If the ``rte_kni`` +kernel module is loaded in :ref:`single kernel thread ` +mode, only one kernel thread is started for all KNI interfaces. The kernel +thread will be bound to the first ``lcore_kthread`` lcore ID specified. -Running the Application ------------------------ +Example Configurations +~~~~~~~~~~~~~~~~~~~~~~~ -The application requires a number of command line options: +The following commands will first load the ``rte_kni`` kernel module in +:ref:`multiple kernel thread ` mode. The ``kni`` +application is then started using two ports; Port 0 uses lcore 4 for the +Rx task, lcore 6 for the Tx task, and will create a single KNI interface +``vEth0_0`` with the kernel thread bound to lcore 8. Port 1 uses lcore +5 for the Rx task, lcore 7 for the Tx task, and will create a single KNI +interface ``vEth1_0`` with the kernel thread bound to lcore 9. .. code-block:: console - kni [EAL options] -- -P -p PORTMASK --config="(port,lcore_rx,lcore_tx[,lcore_kthread,...])[,port,lcore_rx,lcore_tx[,lcore_kthread,...]]" - -Where: + # rmmod rte_kni + # insmod kmod/rte_kni.ko kthread_mode=multiple + # ./build/kni -l 4-7 -n 4 -- -P -p 0x3 -m --config="(0,4,6,8),(1,5,7,9)" -* -P: Set all ports to promiscuous mode so that packets are accepted regardless of the packet's Ethernet MAC destination address. - Without this option, only packets with the Ethernet MAC destination address set to the Ethernet address of the port are accepted. +The following example is identical, except an additional ``lcore_kthread`` +core is specified per physical port. In this case, ``kni`` will create +four KNI interfaces: ``vEth0_0``/``vEth0_1`` bound to physical port 0 and +``vEth1_0``/``vEth1_1`` bound to physical port 1. -* -p PORTMASK: Hexadecimal bitmask of ports to configure. +The kernel thread for each interface will be bound as follows: -* --config="(port,lcore_rx, lcore_tx[,lcore_kthread, ...]) [, port,lcore_rx, lcore_tx[,lcore_kthread, ...]]": - Determines which lcores of RX, TX, kernel thread are mapped to which ports. + * ``vEth0_0`` - bound to lcore 8. + * ``vEth0_1`` - bound to lcore 10. + * ``vEth1_0`` - bound to lcore 9. + * ``vEth1_1`` - bound to lcore 11 -Refer to *DPDK Getting Started Guide* for general information on running applications and the Environment Abstraction Layer (EAL) options. +.. code-block:: console -The -c coremask parameter of the EAL options should include the lcores indicated by the lcore_rx and lcore_tx, -but does not need to include lcores indicated by lcore_kthread as they are used to pin the kernel thread on. -The -p PORTMASK parameter should include the ports indicated by the port in --config, neither more nor less. + # rmmod rte_kni + # insmod kmod/rte_kni.ko kthread_mode=multiple + # ./build/kni -l 4-7 -n 4 -- -P -p 0x3 -m --config="(0,4,6,8,10),(1,5,7,9,11)" -The lcore_kthread in --config can be configured none, one or more lcore IDs. -In multiple kernel thread mode, if configured none, a KNI device will be allocated for each port, -while no specific lcore affinity will be set for its kernel thread. -If configured one or more lcore IDs, one or more KNI devices will be allocated for each port, -while specific lcore affinity will be set for its kernel thread. -In single kernel thread mode, if configured none, a KNI device will be allocated for each port. -If configured one or more lcore IDs, -one or more KNI devices will be allocated for each port while -no lcore affinity will be set as there is only one kernel thread for all KNI devices. +The following example can be used to test the interface between the ``kni`` +test application and the ``rte_kni`` kernel module. In this example, +the ``rte_kni`` kernel module is loaded in :ref:`single kernel thread +mode `, :ref:`loopback mode ` +enabled, and the :ref:`default carrier state ` +is set to *on* so that the corresponding physical NIC port does not have +to be connected in order to use the KNI interface. One KNI interface +``vEth0_0`` is created for port 0 and one KNI interface ``vEth1_0`` is +created for port 1. Since ``rte_kni`` is loaded in "single kernel thread" +mode, the one kernel thread is bound to lcore 8. -For example, to run the application with two ports served by six lcores, one lcore of RX, one lcore of TX, -and one lcore of kernel thread for each port: +Since the physical NIC ports are not being used, link monitoring can be +disabled by **not** specifying the ``-m`` flag to ``kni``: .. code-block:: console - ./build/kni -c 0xf0 -n 4 -- -P -p 0x3 -config="(0,4,6,8),(1,5,7,9)" + # rmmod rte_kni + # insmod kmod/rte_kni.ko lo_mode=lo_mode_fifo carrier=on + # ./build/kni -l 4-7 -n 4 -- -P -p 0x3 --config="(0,4,6,8),(1,5,7,9)" KNI Operations -------------- -Once the KNI application is started, one can use different Linux* commands to manage the net interfaces. -If more than one KNI devices configured for a physical port, -only the first KNI device will be paired to the physical device. -Operations on other KNI devices will not affect the physical port handled in user space application. +Once the ``kni`` application is started, the user can use the normal +Linux commands to manage the KNI interfaces as if they were any other +Linux network interface. -Assigning an IP address: +Enable KNI interface and assign an IP address: .. code-block:: console - #ifconfig vEth0_0 192.168.0.1 + # ip addr add dev vEth0_0 192.168.0.1 -Displaying the NIC registers: +Show KNI interface configuration and statistics: .. code-block:: console - #ethtool -d vEth0_0 + # ip -s -d addr show vEth0_0 -Dumping the network traffic: +The user can also check and reset the packet statistics inside the ``kni`` +application by sending the app the USR1 and USR2 signals: .. code-block:: console - #tcpdump -i vEth0_0 - -When the DPDK userspace application is closed, all the KNI devices are deleted from Linux*. - -Explanation ------------ - -The following sections provide some explanation of code. - -Initialization -~~~~~~~~~~~~~~ - -Setup of mbuf pool, driver and queues is similar to the setup done in the L2 Forwarding sample application -(see Chapter 9 "L2 Forwarding Sample Application (in Real and Virtualized Environments" for details). -In addition, one or more kernel NIC interfaces are allocated for each -of the configured ports according to the command line parameters. + # Print statistics + # pkill -USR1 kni -The code for creating the kernel NIC interface for a specific port is as follows: + # Zero statistics + # pkill -USR2 kni -.. code-block:: c +Dump network traffic: - kni = rte_kni_create(port, MAX_PACKET_SZ, pktmbuf_pool, &kni_ops); - if (kni == NULL) - rte_exit(EXIT_FAILURE, "Fail to create kni dev " - "for port: %d\n", port); +.. code-block:: console -The code for allocating the kernel NIC interfaces for a specific port is as follows: + # tshark -n -i vEth0_0 -.. code-block:: c +The normal Linux commands can also be used to change the MAC address and +MTU size used by the physical NIC which corresponds to the KNI interface. +However, if more than one KNI interface is configured for a physical port, +these commands will only work on the first KNI interface for that port. - static int - kni_alloc(uint8_t port_id) - { - uint8_t i; - struct rte_kni *kni; - struct rte_kni_conf conf; - struct kni_port_params **params = kni_port_params_array; +Change the MAC address: - if (port_id >= RTE_MAX_ETHPORTS || !params[port_id]) - return -1; +.. code-block:: console - params[port_id]->nb_kni = params[port_id]->nb_lcore_k ? params[port_id]->nb_lcore_k : 1; + # ip link set dev vEth0_0 lladdr 0C:01:02:03:04:08 - for (i = 0; i < params[port_id]->nb_kni; i++) { +Change the MTU size: - /* Clear conf at first */ +.. code-block:: console - memset(&conf, 0, sizeof(conf)); - if (params[port_id]->nb_lcore_k) { - rte_snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth%u_%u", port_id, i); - conf.core_id = params[port_id]->lcore_k[i]; - conf.force_bind = 1; - } else - rte_snprintf(conf.name, RTE_KNI_NAMESIZE, "vEth%u", port_id); - conf.group_id = (uint16_t)port_id; - conf.mbuf_size = MAX_PACKET_SZ; + # ip link set dev vEth0_0 mtu 1450 - /* - * The first KNI device associated to a port - * is the master, for multiple kernel thread - * environment. - */ +Limited ethtool support: - if (i == 0) { - struct rte_kni_ops ops; - struct rte_eth_dev_info dev_info; +.. code-block:: console - memset(&dev_info, 0, sizeof(dev_info)); rte_eth_dev_info_get(port_id, &dev_info); + # ethtool -i vEth0_0 - conf.addr = dev_info.pci_dev->addr; - conf.id = dev_info.pci_dev->id; +When the ``kni`` application is closed, all the KNI interfaces are deleted +from the Linux kernel. - memset(&ops, 0, sizeof(ops)); +Explanation +----------- - ops.port_id = port_id; - ops.change_mtu = kni_change_mtu; - ops.config_network_if = kni_config_network_interface; +The following sections provide some explanation of code. - kni = rte_kni_alloc(pktmbuf_pool, &conf, &ops); - } else - kni = rte_kni_alloc(pktmbuf_pool, &conf, NULL); +Initialization +~~~~~~~~~~~~~~ - if (!kni) - rte_exit(EXIT_FAILURE, "Fail to create kni for " - "port: %d\n", port_id); +Setup of mbuf pool, driver and queues is similar to the setup done in the :doc:`l2_forward_real_virtual`.. +In addition, one or more kernel NIC interfaces are allocated for each +of the configured ports according to the command line parameters. - params[port_id]->kni[i] = kni; - } - return 0; - } +The code for allocating the kernel NIC interfaces for a specific port is +in the function ``kni_alloc``. The other step in the initialization process that is unique to this sample application is the association of each port with lcores for RX, TX and kernel threads. @@ -326,105 +295,8 @@ is the association of each port with lcores for RX, TX and kernel threads. * Other lcores for pinning the kernel threads on one by one -This is done by using the`kni_port_params_array[]` array, which is indexed by the port ID. -The code is as follows: - -.. code-block:: console - - static int - parse_config(const char *arg) - { - const char *p, *p0 = arg; - char s[256], *end; - unsigned size; - enum fieldnames { - FLD_PORT = 0, - FLD_LCORE_RX, - FLD_LCORE_TX, - _NUM_FLD = KNI_MAX_KTHREAD + 3, - }; - int i, j, nb_token; - char *str_fld[_NUM_FLD]; - unsigned long int_fld[_NUM_FLD]; - uint8_t port_id, nb_kni_port_params = 0; - - memset(&kni_port_params_array, 0, sizeof(kni_port_params_array)); - - while (((p = strchr(p0, '(')) != NULL) && nb_kni_port_params < RTE_MAX_ETHPORTS) { - p++; - if ((p0 = strchr(p, ')')) == NULL) - goto fail; - - size = p0 - p; - - if (size >= sizeof(s)) { - printf("Invalid config parameters\n"); - goto fail; - } - - rte_snprintf(s, sizeof(s), "%.*s", size, p); - nb_token = rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ','); - - if (nb_token <= FLD_LCORE_TX) { - printf("Invalid config parameters\n"); - goto fail; - } - - for (i = 0; i < nb_token; i++) { - errno = 0; - int_fld[i] = strtoul(str_fld[i], &end, 0); - if (errno != 0 || end == str_fld[i]) { - printf("Invalid config parameters\n"); - goto fail; - } - } - - i = 0; - port_id = (uint8_t)int_fld[i++]; - - if (port_id >= RTE_MAX_ETHPORTS) { - printf("Port ID %u could not exceed the maximum %u\n", port_id, RTE_MAX_ETHPORTS); - goto fail; - } - - if (kni_port_params_array[port_id]) { - printf("Port %u has been configured\n", port_id); - goto fail; - } - - kni_port_params_array[port_id] = (struct kni_port_params*)rte_zmalloc("KNI_port_params", sizeof(struct kni_port_params), RTE_CACHE_LINE_SIZE); - kni_port_params_array[port_id]->port_id = port_id; - kni_port_params_array[port_id]->lcore_rx = (uint8_t)int_fld[i++]; - kni_port_params_array[port_id]->lcore_tx = (uint8_t)int_fld[i++]; - - if (kni_port_params_array[port_id]->lcore_rx >= RTE_MAX_LCORE || kni_port_params_array[port_id]->lcore_tx >= RTE_MAX_LCORE) { - printf("lcore_rx %u or lcore_tx %u ID could not " - "exceed the maximum %u\n", - kni_port_params_array[port_id]->lcore_rx, kni_port_params_array[port_id]->lcore_tx, RTE_MAX_LCORE); - goto fail; - } - - for (j = 0; i < nb_token && j < KNI_MAX_KTHREAD; i++, j++) - kni_port_params_array[port_id]->lcore_k[j] = (uint8_t)int_fld[i]; - kni_port_params_array[port_id]->nb_lcore_k = j; - } - - print_config(); - - return 0; - - fail: - - for (i = 0; i < RTE_MAX_ETHPORTS; i++) { - if (kni_port_params_array[i]) { - rte_free(kni_port_params_array[i]); - kni_port_params_array[i] = NULL; - } - } - - return -1; - - } +This is done by using the ``kni_port_params_array[]`` array, which is indexed by the port ID. +The code is in the function ``parse_config``. Packet Forwarding ~~~~~~~~~~~~~~~~~ @@ -433,188 +305,14 @@ After the initialization steps are completed, the main_loop() function is run on This function first checks the lcore_id against the user provided lcore_rx and lcore_tx to see if this lcore is reading from or writing to kernel NIC interfaces. -For the case that reads from a NIC port and writes to the kernel NIC interfaces, +For the case that reads from a NIC port and writes to the kernel NIC interfaces (``kni_ingress``), the packet reception is the same as in L2 Forwarding sample application -(see Section 9.4.6 "Receive, Process and Transmit Packets"). -The packet transmission is done by sending mbufs into the kernel NIC interfaces by rte_kni_tx_burst(). +(see :ref:`l2_fwd_app_rx_tx_packets`). +The packet transmission is done by sending mbufs into the kernel NIC interfaces by ``rte_kni_tx_burst()``. The KNI library automatically frees the mbufs after the kernel successfully copied the mbufs. -.. code-block:: c - - /** - * Interface to burst rx and enqueue mbufs into rx_q - */ - - static void - kni_ingress(struct kni_port_params *p) - { - uint8_t i, nb_kni, port_id; - unsigned nb_rx, num; - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - - if (p == NULL) - return; - - nb_kni = p->nb_kni; - port_id = p->port_id; - - for (i = 0; i < nb_kni; i++) { - /* Burst rx from eth */ - nb_rx = rte_eth_rx_burst(port_id, 0, pkts_burst, PKT_BURST_SZ); - if (unlikely(nb_rx > PKT_BURST_SZ)) { - RTE_LOG(ERR, APP, "Error receiving from eth\n"); - return; - } - - /* Burst tx to kni */ - num = rte_kni_tx_burst(p->kni[i], pkts_burst, nb_rx); - kni_stats[port_id].rx_packets += num; - rte_kni_handle_request(p->kni[i]); - - if (unlikely(num < nb_rx)) { - /* Free mbufs not tx to kni interface */ - kni_burst_free_mbufs(&pkts_burst[num], nb_rx - num); - kni_stats[port_id].rx_dropped += nb_rx - num; - } - } - } - -For the other case that reads from kernel NIC interfaces and writes to a physical NIC port, packets are retrieved by reading -mbufs from kernel NIC interfaces by `rte_kni_rx_burst()`. +For the other case that reads from kernel NIC interfaces +and writes to a physical NIC port (``kni_egress``), +packets are retrieved by reading mbufs from kernel NIC interfaces by ``rte_kni_rx_burst()``. The packet transmission is the same as in the L2 Forwarding sample application -(see Section 9.4.6 "Receive, Process and Transmit Packet's"). - -.. code-block:: c - - /** - * Interface to dequeue mbufs from tx_q and burst tx - */ - - static void - - kni_egress(struct kni_port_params *p) - { - uint8_t i, nb_kni, port_id; - unsigned nb_tx, num; - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - - if (p == NULL) - return; - - nb_kni = p->nb_kni; - port_id = p->port_id; - - for (i = 0; i < nb_kni; i++) { - /* Burst rx from kni */ - num = rte_kni_rx_burst(p->kni[i], pkts_burst, PKT_BURST_SZ); - if (unlikely(num > PKT_BURST_SZ)) { - RTE_LOG(ERR, APP, "Error receiving from KNI\n"); - return; - } - - /* Burst tx to eth */ - - nb_tx = rte_eth_tx_burst(port_id, 0, pkts_burst, (uint16_t)num); - - kni_stats[port_id].tx_packets += nb_tx; - - if (unlikely(nb_tx < num)) { - /* Free mbufs not tx to NIC */ - kni_burst_free_mbufs(&pkts_burst[nb_tx], num - nb_tx); - kni_stats[port_id].tx_dropped += num - nb_tx; - } - } - } - -Callbacks for Kernel Requests -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To execute specific PMD operations in user space requested by some Linux* commands, -callbacks must be implemented and filled in the struct rte_kni_ops structure. -Currently, setting a new MTU and configuring the network interface (up/ down) are supported. - -.. code-block:: c - - static struct rte_kni_ops kni_ops = { - .change_mtu = kni_change_mtu, - .config_network_if = kni_config_network_interface, - }; - - /* Callback for request of changing MTU */ - - static int - kni_change_mtu(uint8_t port_id, unsigned new_mtu) - { - int ret; - struct rte_eth_conf conf; - - if (port_id >= rte_eth_dev_count()) { - RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id); - return -EINVAL; - } - - RTE_LOG(INFO, APP, "Change MTU of port %d to %u\n", port_id, new_mtu); - - /* Stop specific port */ - - rte_eth_dev_stop(port_id); - - memcpy(&conf, &port_conf, sizeof(conf)); - - /* Set new MTU */ - - if (new_mtu > ETHER_MAX_LEN) - conf.rxmode.jumbo_frame = 1; - else - conf.rxmode.jumbo_frame = 0; - - /* mtu + length of header + length of FCS = max pkt length */ - - conf.rxmode.max_rx_pkt_len = new_mtu + KNI_ENET_HEADER_SIZE + KNI_ENET_FCS_SIZE; - - ret = rte_eth_dev_configure(port_id, 1, 1, &conf); - if (ret < 0) { - RTE_LOG(ERR, APP, "Fail to reconfigure port %d\n", port_id); - return ret; - } - - /* Restart specific port */ - - ret = rte_eth_dev_start(port_id); - if (ret < 0) { - RTE_LOG(ERR, APP, "Fail to restart port %d\n", port_id); - return ret; - } - - return 0; - } - - /* Callback for request of configuring network interface up/down */ - - static int - kni_config_network_interface(uint8_t port_id, uint8_t if_up) - { - int ret = 0; - - if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) { - RTE_LOG(ERR, APP, "Invalid port id %d\n", port_id); - return -EINVAL; - } - - RTE_LOG(INFO, APP, "Configure network interface of %d %s\n", - - port_id, if_up ? "up" : "down"); - - if (if_up != 0) { - /* Configure network interface up */ - rte_eth_dev_stop(port_id); - ret = rte_eth_dev_start(port_id); - } else /* Configure network interface down */ - rte_eth_dev_stop(port_id); - - if (ret < 0) - RTE_LOG(ERR, APP, "Failed to start port %d\n", port_id); - return ret; - } - -.. |kernel_nic| image:: img/kernel_nic.png +(see :ref:`l2_fwd_app_rx_tx_packets`).