15630257fSFerruh Yigit.. SPDX-License-Identifier: BSD-3-Clause 25630257fSFerruh Yigit Copyright(c) 2010-2014 Intel Corporation. 3d0dff9baSBernard Iremonger 4d0dff9baSBernard IremongerLink Status Interrupt Sample Application 5d0dff9baSBernard Iremonger======================================== 6d0dff9baSBernard Iremonger 7*8750576fSNandini PersadThe Link Status Interrupt sample application is an example of packet processing using 8e0c7c473SSiobhan Butlerthe Data Plane Development Kit (DPDK) that 9d0dff9baSBernard Iremongerdemonstrates how network link status changes for a network port can be captured and 10e0c7c473SSiobhan Butlerused by a DPDK application. 11d0dff9baSBernard Iremonger 12d0dff9baSBernard IremongerOverview 13d0dff9baSBernard Iremonger-------- 14d0dff9baSBernard Iremonger 15d0dff9baSBernard IremongerThe Link Status Interrupt sample application registers a user space callback for the link status interrupt of each port 16d0dff9baSBernard Iremongerand performs L2 forwarding for each packet that is received on an RX_PORT. 17*8750576fSNandini Persad 18d0dff9baSBernard IremongerThe following operations are performed: 19d0dff9baSBernard Iremonger 20d0dff9baSBernard Iremonger* RX_PORT and TX_PORT are paired with available ports one-by-one according to the core mask 21d0dff9baSBernard Iremonger 22d0dff9baSBernard Iremonger* The source MAC address is replaced by the TX_PORT MAC address 23d0dff9baSBernard Iremonger 24d0dff9baSBernard Iremonger* The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID 25d0dff9baSBernard Iremonger 26d0dff9baSBernard IremongerThis application can be used to demonstrate the usage of link status interrupt and its user space callbacks 27d0dff9baSBernard Iremongerand the behavior of L2 forwarding each time the link status changes. 28d0dff9baSBernard Iremonger 29d0dff9baSBernard IremongerCompiling the Application 30d0dff9baSBernard Iremonger------------------------- 31d0dff9baSBernard Iremonger 32*8750576fSNandini PersadTo compile the sample application, see :doc:`compiling`. 33d0dff9baSBernard Iremonger 347cacb056SHerakliusz LipiecThe application is located in the ``link_status_interrupt`` sub-directory. 35d0dff9baSBernard Iremonger 36d0dff9baSBernard IremongerRunning the Application 37d0dff9baSBernard Iremonger----------------------- 38d0dff9baSBernard Iremonger 39d0dff9baSBernard IremongerThe application requires a number of command line options: 40d0dff9baSBernard Iremonger 41d0dff9baSBernard Iremonger.. code-block:: console 42d0dff9baSBernard Iremonger 43e2a94f9aSCiara Power ./<build_dir>/examples/dpdk-link_status_interrupt [EAL options] -- -p PORTMASK [-q NQ][-T PERIOD] 44d0dff9baSBernard Iremonger 45d0dff9baSBernard Iremongerwhere, 46d0dff9baSBernard Iremonger 47d0dff9baSBernard Iremonger* -p PORTMASK: A hexadecimal bitmask of the ports to configure 48d0dff9baSBernard Iremonger 49885807aeSStephen Hemminger* -q NQ: Maximum number of queues per lcore (default is 1) 50d0dff9baSBernard Iremonger 51d0dff9baSBernard Iremonger* -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default) 52d0dff9baSBernard Iremonger 53218c4e68SBruce RichardsonTo run the application in a linux environment with 4 lcores, 4 memory channels, 16 ports and 8 RX queues per lcore, 54d0dff9baSBernard Iremongerissue the command: 55d0dff9baSBernard Iremonger 56d0dff9baSBernard Iremonger.. code-block:: console 57d0dff9baSBernard Iremonger 58e2a94f9aSCiara Power $ ./<build_dir>/examples/dpdk-link_status_interrupt -l 0-3 -n 4-- -q 8 -p ffff 59d0dff9baSBernard Iremonger 60e0c7c473SSiobhan ButlerRefer to the *DPDK Getting Started Guide* for general information on running applications 61d0dff9baSBernard Iremongerand the Environment Abstraction Layer (EAL) options. 62d0dff9baSBernard Iremonger 63d0dff9baSBernard IremongerExplanation 64d0dff9baSBernard Iremonger----------- 65d0dff9baSBernard Iremonger 66d0dff9baSBernard IremongerThe following sections provide some explanation of the code. 67d0dff9baSBernard Iremonger 68d0dff9baSBernard IremongerCommand Line Arguments 69d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~ 70d0dff9baSBernard Iremonger 71*8750576fSNandini PersadThe Link Status Interrupt sample application takes specific parameters 72*8750576fSNandini Persadand Environment Abstraction Layer (EAL) arguments (see Section `Running the Application`_). 73d0dff9baSBernard Iremonger 74d0dff9baSBernard IremongerCommand line parsing is done in the same way as it is done in the L2 Forwarding Sample Application. 75513b0723SMauricio Vasquez BSee :ref:`l2_fwd_app_cmd_arguments` for more information. 76d0dff9baSBernard Iremonger 77d0dff9baSBernard IremongerMbuf Pool Initialization 78d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~~ 79d0dff9baSBernard Iremonger 80d0dff9baSBernard IremongerMbuf pool initialization is done in the same way as it is done in the L2 Forwarding Sample Application. 81513b0723SMauricio Vasquez BSee :ref:`l2_fwd_app_mbuf_init` for more information. 82d0dff9baSBernard Iremonger 83d0dff9baSBernard IremongerDriver Initialization 84d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~ 85d0dff9baSBernard Iremonger 86d0dff9baSBernard IremongerThe main part of the code in the main() function relates to the initialization of the driver. 87d0dff9baSBernard IremongerTo fully understand this code, it is recommended to study the chapters that related to the Poll Mode Driver in the 88e0c7c473SSiobhan Butler*DPDK Programmer's Guide and the DPDK API Reference*. 89d0dff9baSBernard Iremonger 909a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 919a212dc0SConor Fogarty :language: c 929a212dc0SConor Fogarty :start-after: Each logical core is assigned a dedicated TX queue on each port. 8< 939a212dc0SConor Fogarty :end-before: >8 End of assigning logical core. 949a212dc0SConor Fogarty :dedent: 1 95d0dff9baSBernard Iremonger 96d0dff9baSBernard IremongerThe next step is to configure the RX and TX queues. 97d0dff9baSBernard IremongerFor each port, there is only one RX queue (only one lcore is able to poll a given port). 98d0dff9baSBernard IremongerThe number of TX queues depends on the number of available lcores. 99d0dff9baSBernard IremongerThe rte_eth_dev_configure() function is used to configure the number of queues for a port: 100d0dff9baSBernard Iremonger 1019a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1029a212dc0SConor Fogarty :language: c 1039a212dc0SConor Fogarty :start-after: Configure RX and TX queues. 8< 1049a212dc0SConor Fogarty :end-before: >8 End of configure RX and TX queues. 1059a212dc0SConor Fogarty :dedent: 2 106d0dff9baSBernard Iremonger 107d0dff9baSBernard IremongerThe global configuration is stored in a static structure: 108d0dff9baSBernard Iremonger 1099a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1109a212dc0SConor Fogarty :language: c 1119a212dc0SConor Fogarty :start-after: Global configuration stored in a static structure. 8< 1129a212dc0SConor Fogarty :end-before: >8 End of global configuration stored in a static structure. 113d0dff9baSBernard Iremonger 114d0dff9baSBernard IremongerConfiguring lsc to 0 (the default) disables the generation of any link status change interrupts in kernel space 115d0dff9baSBernard Iremongerand no user space interrupt event is received. 116d0dff9baSBernard IremongerThe public interface rte_eth_link_get() accesses the NIC registers directly to update the link status. 117d0dff9baSBernard IremongerConfiguring lsc to non-zero enables the generation of link status change interrupts in kernel space 118d0dff9baSBernard Iremongerwhen a link status change is present and calls the user space callbacks registered by the application. 119d0dff9baSBernard IremongerThe public interface rte_eth_link_get() just reads the link status in a global structure 120d0dff9baSBernard Iremongerthat would be updated in the interrupt host thread only. 121d0dff9baSBernard Iremonger 122d0dff9baSBernard IremongerInterrupt Callback Registration 123d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 124d0dff9baSBernard Iremonger 125d0dff9baSBernard IremongerThe application can register one or more callbacks to a specific port and interrupt event. 126d0dff9baSBernard IremongerAn example callback function that has been written as indicated below. 127d0dff9baSBernard Iremonger 1289a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1299a212dc0SConor Fogarty :language: c 1309a212dc0SConor Fogarty :start-after: lsi_event_callback 8< 1319a212dc0SConor Fogarty :end-before: >8 End of registering one or more callbacks. 132d0dff9baSBernard Iremonger 133d0dff9baSBernard IremongerThis function is called when a link status interrupt is present for the right port. 134d0dff9baSBernard IremongerThe port_id indicates which port the interrupt applies to. 135d0dff9baSBernard IremongerThe type parameter identifies the interrupt event type, 136d0dff9baSBernard Iremongerwhich currently can be RTE_ETH_EVENT_INTR_LSC only, but other types can be added in the future. 137d0dff9baSBernard IremongerThe param parameter is the address of the parameter for the callback. 138d0dff9baSBernard IremongerThis function should be implemented with care since it will be called in the interrupt host thread, 139d0dff9baSBernard Iremongerwhich is different from the main thread of its caller. 140d0dff9baSBernard Iremonger 141d0dff9baSBernard IremongerThe application registers the lsi_event_callback and a NULL parameter to the link status interrupt event on each port: 142d0dff9baSBernard Iremonger 1439a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1449a212dc0SConor Fogarty :language: c 1459a212dc0SConor Fogarty :start-after: RTE callback register. 8< 1469a212dc0SConor Fogarty :end-before: >8 End of registering lsi interrupt callback. 1479a212dc0SConor Fogarty :dedent: 2 148d0dff9baSBernard Iremonger 149d0dff9baSBernard IremongerThis registration can be done only after calling the rte_eth_dev_configure() function and before calling any other function. 150d0dff9baSBernard IremongerIf lsc is initialized with 0, the callback is never called since no interrupt event would ever be present. 151d0dff9baSBernard Iremonger 152d0dff9baSBernard IremongerRX Queue Initialization 153d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~ 154d0dff9baSBernard Iremonger 155d0dff9baSBernard IremongerThe application uses one lcore to poll one or several ports, depending on the -q option, 156d0dff9baSBernard Iremongerwhich specifies the number of queues per lcore. 157d0dff9baSBernard Iremonger 158d0dff9baSBernard IremongerFor example, if the user specifies -q 4, the application is able to poll four ports with one lcore. 159d0dff9baSBernard IremongerIf there are 16 ports on the target (and if the portmask argument is -p ffff), 160d0dff9baSBernard Iremongerthe application will need four lcores to poll all the ports. 161d0dff9baSBernard Iremonger 1629a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1639a212dc0SConor Fogarty :language: c 1649a212dc0SConor Fogarty :start-after: RX queue initialization. 8< 1659a212dc0SConor Fogarty :end-before: >8 End of RX queue initialization. 1669a212dc0SConor Fogarty :dedent: 2 167d0dff9baSBernard Iremonger 168d0dff9baSBernard IremongerThe list of queues that must be polled for a given lcore is stored in a private structure called struct lcore_queue_conf. 169d0dff9baSBernard Iremonger 1709a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1719a212dc0SConor Fogarty :language: c 1729a212dc0SConor Fogarty :start-after: List of queues must be polled for a give lcore. 8< 1739a212dc0SConor Fogarty :end-before: >8 End of list of queues to be polled. 174d0dff9baSBernard Iremonger 175d0dff9baSBernard IremongerThe n_rx_port and rx_port_list[] fields are used in the main packet processing loop 176513b0723SMauricio Vasquez B(see `Receive, Process and Transmit Packets`_). 177d0dff9baSBernard Iremonger 178d0dff9baSBernard IremongerThe global configuration for the RX queues is stored in a static structure: 179d0dff9baSBernard Iremonger 1809a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1819a212dc0SConor Fogarty :language: c 1829a212dc0SConor Fogarty :start-after: List of queues must be polled for a give lcore. 8< 1839a212dc0SConor Fogarty :end-before: >8 End of list of queues to be polled. 184d0dff9baSBernard Iremonger 185d0dff9baSBernard IremongerTX Queue Initialization 186d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~ 187d0dff9baSBernard Iremonger 188d0dff9baSBernard IremongerEach lcore should be able to transmit on any port. 189d0dff9baSBernard IremongerFor every port, a single TX queue is initialized. 190d0dff9baSBernard Iremonger 1919a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 1929a212dc0SConor Fogarty :language: c 1939a212dc0SConor Fogarty :start-after: init one TX queue logical core on each port. 8< 1949a212dc0SConor Fogarty :end-before: >8 End of init one TX queue. 1959a212dc0SConor Fogarty :dedent: 2 196d0dff9baSBernard Iremonger 197d0dff9baSBernard IremongerThe global configuration for TX queues is stored in a static structure: 198d0dff9baSBernard Iremonger 199d0dff9baSBernard Iremonger.. code-block:: c 200d0dff9baSBernard Iremonger 201d0dff9baSBernard Iremonger static const struct rte_eth_txconf tx_conf = { 202d0dff9baSBernard Iremonger .tx_thresh = { 203d0dff9baSBernard Iremonger .pthresh = TX_PTHRESH, 204d0dff9baSBernard Iremonger .hthresh = TX_HTHRESH, 205d0dff9baSBernard Iremonger .wthresh = TX_WTHRESH, 206d0dff9baSBernard Iremonger }, 2074ed89049SDavid Marchand .tx_free_thresh = TX_DESC_DEFAULT + 1, /* disable feature */ 208d0dff9baSBernard Iremonger }; 209d0dff9baSBernard Iremonger 210d0dff9baSBernard IremongerReceive, Process and Transmit Packets 211d0dff9baSBernard Iremonger~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 212d0dff9baSBernard Iremonger 213d0dff9baSBernard IremongerIn the lsi_main_loop() function, the main task is to read ingress packets from the RX queues. 214d0dff9baSBernard IremongerThis is done using the following code: 215d0dff9baSBernard Iremonger 2169a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 2179a212dc0SConor Fogarty :language: c 2189a212dc0SConor Fogarty :start-after: Read packet from RX queues. 8< 2199a212dc0SConor Fogarty :end-before: >8 End of reading packet from RX queues. 2209a212dc0SConor Fogarty :dedent: 2 221d0dff9baSBernard Iremonger 222d0dff9baSBernard IremongerPackets are read in a burst of size MAX_PKT_BURST. 223d0dff9baSBernard IremongerThe rte_eth_rx_burst() function writes the mbuf pointers in a local table and returns the number of available mbufs in the table. 224d0dff9baSBernard Iremonger 225d0dff9baSBernard IremongerThen, each mbuf in the table is processed by the lsi_simple_forward() function. 226d0dff9baSBernard IremongerThe processing is very simple: processes the TX port from the RX port and then replaces the source and destination MAC addresses. 227d0dff9baSBernard Iremonger 228d0dff9baSBernard Iremonger.. note:: 229d0dff9baSBernard Iremonger 230d0dff9baSBernard Iremonger In the following code, the two lines for calculating the output port require some explanation. 231d0dff9baSBernard Iremonger If portId is even, the first line does nothing (as portid & 1 will be 0), and the second line adds 1. 232d0dff9baSBernard Iremonger If portId is odd, the first line subtracts one and the second line does nothing. 233d0dff9baSBernard Iremonger Therefore, 0 goes to 1, and 1 to 0, 2 goes to 3 and 3 to 2, and so on. 234d0dff9baSBernard Iremonger 2359a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 2369a212dc0SConor Fogarty :language: c 2379a212dc0SConor Fogarty :start-after: Replacing the source and destination MAC addresses. 8< 2389a212dc0SConor Fogarty :end-before: >8 End of replacing the source and destination MAC addresses. 239d0dff9baSBernard Iremonger 240d0dff9baSBernard IremongerThen, the packet is sent using the lsi_send_packet(m, dst_port) function. 241d0dff9baSBernard IremongerFor this test application, the processing is exactly the same for all packets arriving on the same RX port. 242d0dff9baSBernard IremongerTherefore, it would have been possible to call the lsi_send_burst() function directly from the main loop 243d0dff9baSBernard Iremongerto send all the received packets on the same TX port using 244d0dff9baSBernard Iremongerthe burst-oriented send function, which is more efficient. 245d0dff9baSBernard Iremonger 246d0dff9baSBernard IremongerHowever, in real-life applications (such as, L3 routing), 247d0dff9baSBernard Iremongerpacket N is not necessarily forwarded on the same port as packet N-1. 248d0dff9baSBernard IremongerThe application is implemented to illustrate that so the same approach can be reused in a more complex application. 249d0dff9baSBernard Iremonger 250d0dff9baSBernard IremongerThe lsi_send_packet() function stores the packet in a per-lcore and per-txport table. 251d0dff9baSBernard IremongerIf the table is full, the whole packets table is transmitted using the lsi_send_burst() function: 252d0dff9baSBernard Iremonger 2539a212dc0SConor Fogarty.. literalinclude:: ../../../examples/l2fwd-crypto/main.c 2549a212dc0SConor Fogarty :language: c 2559a212dc0SConor Fogarty :start-after: Enqueue packets for TX and prepare them to be sent. 8< 2569a212dc0SConor Fogarty :end-before: >8 End of Enqueuing packets for TX. 257d0dff9baSBernard Iremonger 258d0dff9baSBernard IremongerTo ensure that no packets remain in the tables, each lcore does a draining of the TX queue in its main loop. 259d0dff9baSBernard IremongerThis technique introduces some latency when there are not many packets to send. 260d0dff9baSBernard IremongerHowever, it improves performance: 261d0dff9baSBernard Iremonger 2629a212dc0SConor Fogarty.. literalinclude:: ../../../examples/link_status_interrupt/main.c 2639a212dc0SConor Fogarty :language: c 2649a212dc0SConor Fogarty :start-after: Draining TX queue in its main loop. 8< 2659a212dc0SConor Fogarty :end-before: >8 End of draining TX queue in its main loop. 2669a212dc0SConor Fogarty :dedent: 2 267