{"id":1938,"date":"2016-01-22T17:51:06","date_gmt":"2016-01-23T01:51:06","guid":{"rendered":"https:\/\/www.privateinternetaccess.com\/blog\/?p=1938"},"modified":"2024-02-01T01:10:57","modified_gmt":"2024-02-01T09:10:57","slug":"linux-networking-stack-from-the-ground-up-part-2","status":"publish","type":"post","link":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/","title":{"rendered":"Linux networking stack from the ground up, part 2"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-1\/\">part 1<\/a> | <a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\">part 2<\/a> | <a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-3\/\">part 3<\/a> | <a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-4\/\">part 4<\/a> | <a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-4-2\/\">part 5<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Overview<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This post will pick up where part 1 left off, beginning by explaining what <code>ethtool<\/code> is, how device drivers register code for <code>ethtool<\/code>, how drivers enable NAPI, and how drivers enable interrupts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ethtool setup<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ethtool<\/code> is a command line program you can use to get and set driver<br>information. You can install it on Ubuntu by running <code>apt-get install ethtool<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some <code>ethtool<\/code> settings of interest will be described later in this document.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> program talks to device drivers by using the <code>ioctl<\/code> system call.<br>The device drivers register a series of functions that run for the <code>ethtool<\/code> operations and the kernel provides the glue.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When an <code>ioctl<\/code> call is made from <code>ethtool<\/code>, the kernel finds the <code>ethtool<\/code> structure registered by the appropriate driver and executes the functions registered.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">e1000e<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>e1000e<\/code> driver in the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L6627\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:6627<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">e1000e_set_ethtool_ops(netdev);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Which registers a structure of function pointers for each of the ethtool functions supported by <code>e1000e<\/code> (accessing stats, changing ring buffer sizes, etc) from <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/ethtool.c#L2316\">drivers\/net\/ethernet\/intel\/e1000e\/ethtool.c:2316<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">igb<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>igb<\/code> driver in the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/igb\/igb_main.c#L2091\">drivers\/net\/ethernet\/intel\/igb\/igb_main.c:2091<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">igb_set_ethtool_ops(netdev);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">From <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/igb\/igb_main.c#L1905-L1928\">drivers\/net\/ethernet\/intel\/igb\/igb_ethtool.c:1905<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ixgbe<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>ixgbe<\/code> driver in the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_main.c#L7883\">drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_main.c:7883<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ixgbe_set_ethtool_ops(netdev);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">From <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_main.c#L7642-L7686\">drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_ethtool.c:7686<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">tg3<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>tg3<\/code> driver in the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/broadcom\/tg3.c#L17436\">drivers\/net\/ethernet\/broadcom\/tg3.c:17456<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">dev-&gt;ethtool_ops = &amp;tg3_ethtool_ops;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">be2net<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>be2net<\/code> driver in a function called from the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/emulex\/benet\/be_main.c#L4108\">drivers\/net\/ethernet\/emulex\/benet\/be_main.c:4094<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">SET_ETHTOOL_OPS(netdev, &amp;be_ethtool_ops);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">bnx2<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ethtool<\/code> functions are installed in the <code>bnx2<\/code> driver in a function called from the PCI <code>probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/broadcom\/bnx2.c#L8510\">drivers\/net\/ethernet\/broadcom\/bnx2.c:8539<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">dev-&gt;ethtool_ops = &amp;bnx2_ethtool_ops;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">NAPI poll<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Prior to the existence of NAPI, NICs would generate an interrupt for each packet received indicating that data is available to be processed by the kernel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/wiki.linuxfoundation.org\/networking\/napi\">NAPI<\/a> changes this by allowing a device driver to register a <code>poll<\/code> function that the NAPI subsystem will call to harvest packets. This method of gathering packets has reduced overhead compared to the older method, as many packets can be consumed at a time instead of processing only a single packet per interrupt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The device driver implements a <code>poll<\/code> function and registers it with NAPI using <code>netif_napi_add<\/code>. When registering a NAPI <code>poll<\/code> function with <code>netif_napi_add<\/code>, the driver will also specify the \u201cweight\u201d. Most of the drivers hardcode a value of <code>64<\/code>. this value and its meaning will be described in more detail below.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Typically, drivers register their NAPI <code>poll<\/code> functions during driver initialization. In the drivers this document examines, the <code>poll<\/code> function is registered in the PCI <code>probe<\/code> function itself or in a helper function called from there.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">e1000e<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>e1000e<\/code> driver registers its NAPI <code>poll<\/code> function in the <code>e1000_probe<\/code> function (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L6629\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:6629<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(netdev, &amp;adapter-&gt;napi, e1000e_poll, 64);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>e1000e<\/code> registers a single NAPI <code>poll<\/code> function because this device supports only a single receive queue. All of the other drivers being examined support multiple receive queues and will call this function to register multiple NAPI <code>poll<\/code> functions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">igb<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>igb<\/code> driver registers its NAPI <code>poll<\/code> function in <code>igb_alloc_q_vector<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/igb\/igb_main.c#L1180\">drivers\/net\/ethernet\/intel\/igb\/igb_main.c:1180<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(adapter-&gt;netdev, &amp;q_vector-&gt;napi, igb_poll, 64);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This function is called from <code>igb_alloc_q_vectors<\/code>. <code>igb_alloc_q_vector<\/code> is called multiple times to initialize each of the RX and TX queues. <code>igb_alloc_q_vectors<\/code> is called from <code>igb_init_interrupt_scheme<\/code> which is called from several locations, one of which is <code>igb_probe<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ixgbe<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>ixgbe<\/code> driver registers its NAPI <code>poll<\/code> function in <code>ixgbe_alloc_q_vector<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_lib.c#L813-L814\">drivers\/net\/ethernet\/intel\/ixgbe\/ixgbe_lib.c:813<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(adapter-&gt;netdev, &amp;q_vector-&gt;napi, ixgbe_poll, 64);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Similar to <code>igb<\/code>, this function is called from <code>ixgbe_alloc_q_vectors<\/code> and it is called multiple times to initialize each of the RX and TX queues. <code>ixgbe_alloc_q_vectors<\/code> is called from <code>ixgbe_init_interrupt_scheme<\/code> which is called from several locations, once of which is <code>ixgbe_probe<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">tg3<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>tg3<\/code> driver registers its NAPI <code>poll<\/code> function in <code>tg3_napi_init<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/broadcom\/tg3.c#L7366\">drivers\/net\/ethernet\/broadcom\/tg3.c:7366<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(tp-&gt;dev, &amp;tp-&gt;napi[i].napi, tg3_poll_msix, 64);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is called within a loop registering a NAPI <code>poll<\/code> function for each RX and TX queue. It is called from <code>tg3_start<\/code>, which is called from <code>tg3_open<\/code>. Unlike the other drivers, <code>tg3<\/code> registers its NAPI <code>poll<\/code> function in <code>ndo_open<\/code> and not in PCI <code>probe<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">be2net<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>be2net<\/code> driver registers its NAPI <code>poll<\/code> function in <code>be_evt_queues_create<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/emulex\/benet\/be_main.c#L2053-L2054\">drivers\/net\/ethernet\/emulex\/benet\/be_main.c:2053<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(adapter-&gt;netdev, &amp;eqo-&gt;napi, be_poll, BE_NAPI_WEIGHT);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is called within a loop registering a NAPI <code>poll<\/code> function for each RX and TX queue. It is called from <code>be_setup_queues<\/code>, which is called from <code>be_setup<\/code>, which is called from <code>be_probe<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">bnx2<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>bnx2<\/code> driver registers its NAPI <code>poll<\/code> function in <code>bnx2_init_napi<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/broadcom\/bnx2.c#L8464\">drivers\/net\/ethernet\/broadcom\/bnx2.c:6322<\/a>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netif_napi_add(bp-&gt;dev, &amp;bp-&gt;bnx2_napi[i].napi, poll, 64);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is called within a loop registering a NAPI <code>poll<\/code> function for each RX and TX queue. Like <code>tg3<\/code>, <code>bnx2<\/code> allocates queue memory in its <code>ndo_open<\/code> function <code>bnx2_open<\/code> and not in PCI <code>probe<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Interrupt number<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The interrupt number is obtained from the <code>struct pci_dev<\/code> structure and stored on the <code>net_device<\/code> structure:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">netdev-&gt;irq = pdev-&gt;irq;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Later in device initialization the IRQ handlers for this IRQ number will be registered<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Driver initialization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When a network device is brought up (for example, with <code>ifconfig eth0 up<\/code>), an <code>open<\/code> function is called in the device driver. A pointer to this function is installed in a <code>net_device_ops<\/code> structure at a field named <code>ndo_open<\/code>. In e1000e, this function is called <code>e1000_open<\/code> (<a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L4241-L4352\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:4241<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The open function will typically do things like:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Allocate RX and TX queue memory<\/li><li>Enable NAPI<\/li><li>Register an interrupt handler<\/li><li>Enable hardware interrupts<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">And more.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Allocating RX and TX queue memory<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For example, the e1000e driver (found in <a href=\"https:\/\/github.com\/torvalds\/linux\/tree\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\">drivers\/net\/ethernet\/intel\/e1000e\/<\/a>) in <code>netdev.c<\/code> <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L4269\">around line 4279<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\/* allocate transmit descriptors *\/\nerr = e1000e_setup_tx_resources(adapter-&gt;tx_ring);\nif (err)\n  goto err_setup_tx;\n\n\/* allocate receive descriptors *\/\nerr = e1000e_setup_rx_resources(adapter-&gt;rx_ring);\nif (err)\n  goto err_setup_rx;\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>e1000e_setup_rx_resources<\/code> and <code>e1000e_setup_tx_resources<\/code> allocate receive and transmit queues and initialize associated data structures. It is important to note that these queues are read and written directly from the NIC via DMA. In other words: when data arrives from the network, the data is written directly to the receive queue by the NIC via DMA. The queue size is defaulted to <code>E1000_DEFAULT_RXD<\/code> (256) and the max is <code>E1000_MAX_RXD<\/code> (4096). These values are driver specific.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If data arrives faster than it can be processed, it will fill the queue. Once the queue is full, additional data that arrives will be dropped.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can determine if drops are happening and increase the queue size by using the command line tool <code>ethtool<\/code>. <code>ethtool<\/code> communicates with the device driver by using the <code>ioctl<\/code> system call.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Most drivers have a file named <code>ethtool.c<\/code> or <code>*_ethtool.c<\/code> implementing this interface. Not all drivers implement every possible <code>ethtool<\/code> method, so you should check the driver code and <code>ethtool<\/code> output to determine if what you are doing is supported by the driver or not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can get stats from <code>ethtool<\/code> by using the -S flag, for example:<br><code><\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ethtool -S eth0<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The names of the stats will differ from driver to driver, so you should read the output carefully and grep for things like \u201cdrop\u201d \u201cmiss\u201d and \u201cerror\u201d.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As far as e1000e is concerned:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>the <code>rx_no_buffer_count<\/code> statistic (also known as RNBC) indicates that there was nowhere to DMA the packet. Increasing the rx ring (explained below) can help reduce the number of <code>rx_no_buffer_count<\/code> seen over time.<\/li><li>the <code>rx_missed_errors<\/code> statistic indicates that <code>rx_no_buffer_count<\/code> happened enough times that packets were dropped. increasing the rx queue size can help reduce this count.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">To increase the rx (or tx) queue size, you can run:<br><code><\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ethtool -G eth0 rx 4096<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To increase the rx queue for <code>eth0<\/code> to <code>4096<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some NICs have multiple RX and TX queues for added performance. We\u2019ll see shortly why having more than one queue for RX can be beneficial.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can check if your NIC supports multiple queues by using <code>ethtool<\/code> and the <code>-l<\/code> flag:<br><code><\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ethtool -l eth0<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can increase the number of queues by using the <code>-L<\/code> flag:<br><code><\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ethtool -L eth0 rx 8<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that not all device drivers support this <code>ethtool<\/code> function so you may need to consult your device driver source code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enable NAPI<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">e1000e enables NAPI by calling <code>napi_enable<\/code> (from <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L4322\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:4332<\/a>) a static inline function (from <code>include\/linux\/netdevice.h:500<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">napi_enable(&amp;adapter-&gt;napi);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This simply clears a bit on the <code>state<\/code> field of the <code>napi_struct<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Register an interrupt handler<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">There are different methods a device can use to signal an interrupt: MSI-X, MSI, and legacy interrupts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The driver must determine which method is supported by the device and register the appropriate handler function that will execute when the interrupt is received.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The e1000e driver tries to register an MSI-X interrupt handler first, falling back to MSI on failure, falling back again to a legacy interrupt handler if MSI handler registration fails.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This logic is abstracted into <code>e1000_request_irq<\/code> which is called during driver initialization (from <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L4303\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:4303<\/a>) and can be found at <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L2132\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:2132<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MSI-X interrupts are the preferred method, especially for NICs that support multiple RX and TX queues. This is because each RX and TX queue can have its own hardware interrupt assigned, which can then be handled by a specific CPU (with irqbalance or by modifying <code>\/proc\/irq\/IRQ_NUMBER\/smp_affinity<\/code>). In this way, arriving packets can be processed by separate CPUs from the hardware interrupt level.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If MSI-X is unavailable, MSI still presents advantages over legacy interrupts (read more <a href=\"https:\/\/en.wikipedia.org\/wiki\/Message_Signaled_Interrupts#Advantages\">here<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Message_Signaled_Interrupts#MSI_types\">here<\/a>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the e1000e driver, the functions <code>e1000_intr_msix_rx<\/code>, <code>e1000_intr_msi<\/code>, and <code>e1000_intr<\/code> are the interrupt handler methods used for the MSI-X, MSI, and legacy interrupt modes, respectively.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The handler is registered to the IRQ number obtain when PCI system called the <code>probe<\/code> function earlier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, the registration of the interrupt handler for an MSI interrupt from <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/v3.13\/drivers\/net\/ethernet\/intel\/e1000e\/netdev.c#L2147\">drivers\/net\/ethernet\/intel\/e1000e\/netdev.c:2147<\/a>:<br><code><\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">err = request_irq(adapter-&gt;pdev-&gt;irq, e1000_intr_msi, 0, netdev-&gt;name, netdev);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Enable interrupts<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, once initialization is complete, interrupts are enabled on the device. Incoming packets will now trigger an interrupt to be raised, causing the function registered above to be executed to handle the incoming data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enabling interrupts is device specific, but on e1000e the <code>e1000_irq_enable<\/code> function is called which writes a value to a device register to enable interrupts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device drivers register code for ethtool, how drivers enable NAPI, and how drivers enable interrupts. ethtool setup ethtool is a command line program &hellip; <a href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Linux networking stack from the ground up, part 2&#8221;<\/span><\/a><\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_stopmodifiedupdate":false,"_modified_date":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-1938","post","type-post","status-publish","format-standard","hentry","category-news"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Linux networking stack from the ground up, part 2<\/title>\n<meta name=\"description\" content=\"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Linux networking stack from the ground up, part 2\" \/>\n<meta property=\"og:description\" content=\"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"PIA\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/privateinternetaccess\/\" \/>\n<meta property=\"article:published_time\" content=\"2016-01-23T01:51:06+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-01T09:10:57+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/ogimage.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"PIA Research\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@buyvpnservice\" \/>\n<meta name=\"twitter:site\" content=\"@buyvpnservice\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"PIA Research\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\"},\"author\":{\"name\":\"PIA Research\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/867d81a36eafaf83e91f6528aca0ba29\"},\"headline\":\"Linux networking stack from the ground up, part 2\",\"datePublished\":\"2016-01-23T01:51:06+00:00\",\"dateModified\":\"2024-02-01T09:10:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\"},\"wordCount\":1562,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#organization\"},\"articleSection\":[\"General Privacy News\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\",\"url\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\",\"name\":\"Linux networking stack from the ground up, part 2\",\"isPartOf\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#website\"},\"datePublished\":\"2016-01-23T01:51:06+00:00\",\"dateModified\":\"2024-02-01T09:10:57+00:00\",\"description\":\"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device\",\"breadcrumb\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.privateinternetaccess.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Linux networking stack from the ground up, part 2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#website\",\"url\":\"https:\/\/www.privateinternetaccess.com\/blog\/\",\"name\":\"PIA\",\"description\":\"Online privacy news from around the world.\",\"publisher\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.privateinternetaccess.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#organization\",\"name\":\"Private Internet Access\",\"url\":\"https:\/\/www.privateinternetaccess.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/pialogowhitekglogo.png\",\"contentUrl\":\"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/pialogowhitekglogo.png\",\"width\":1200,\"height\":1200,\"caption\":\"Private Internet Access\"},\"image\":{\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/privateinternetaccess\/\",\"https:\/\/x.com\/buyvpnservice\",\"https:\/\/www.instagram.com\/piavpn\/\",\"https:\/\/www.youtube.com\/channel\/UClyJZ47Rizb1xnwuKXDI0_w\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/867d81a36eafaf83e91f6528aca0ba29\",\"name\":\"PIA Research\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/717a02042be28ce22f2ae82923cdaa82551205b8768e3cd4a8fce14988ed0ccd?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/717a02042be28ce22f2ae82923cdaa82551205b8768e3cd4a8fce14988ed0ccd?s=96&d=mm&r=g\",\"caption\":\"PIA Research\"},\"sameAs\":[\"https:\/\/www.privateinternetaccess.com\"],\"url\":\"https:\/\/www.privateinternetaccess.com\/blog\/author\/piaresearch\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Linux networking stack from the ground up, part 2","description":"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/","og_locale":"en_US","og_type":"article","og_title":"Linux networking stack from the ground up, part 2","og_description":"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device","og_url":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/","og_site_name":"PIA","article_publisher":"https:\/\/www.facebook.com\/privateinternetaccess\/","article_published_time":"2016-01-23T01:51:06+00:00","article_modified_time":"2024-02-01T09:10:57+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/ogimage.png","type":"image\/png"}],"author":"PIA Research","twitter_card":"summary_large_image","twitter_creator":"@buyvpnservice","twitter_site":"@buyvpnservice","twitter_misc":{"Written by":"PIA Research","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#article","isPartOf":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/"},"author":{"name":"PIA Research","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/867d81a36eafaf83e91f6528aca0ba29"},"headline":"Linux networking stack from the ground up, part 2","datePublished":"2016-01-23T01:51:06+00:00","dateModified":"2024-02-01T09:10:57+00:00","mainEntityOfPage":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/"},"wordCount":1562,"commentCount":0,"publisher":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/#organization"},"articleSection":["General Privacy News"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/","url":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/","name":"Linux networking stack from the ground up, part 2","isPartOf":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/#website"},"datePublished":"2016-01-23T01:51:06+00:00","dateModified":"2024-02-01T09:10:57+00:00","description":"part 1 | part 2 | part 3 | part 4 | part 5 Overview This post will pick up where part 1 left off, beginning by explaining what ethtool is, how device","breadcrumb":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.privateinternetaccess.com\/blog\/linux-networking-stack-from-the-ground-up-part-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.privateinternetaccess.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Linux networking stack from the ground up, part 2"}]},{"@type":"WebSite","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#website","url":"https:\/\/www.privateinternetaccess.com\/blog\/","name":"PIA","description":"Online privacy news from around the world.","publisher":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.privateinternetaccess.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#organization","name":"Private Internet Access","url":"https:\/\/www.privateinternetaccess.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/pialogowhitekglogo.png","contentUrl":"https:\/\/www.privateinternetaccess.com\/blog\/wp-content\/uploads\/2018\/07\/pialogowhitekglogo.png","width":1200,"height":1200,"caption":"Private Internet Access"},"image":{"@id":"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/privateinternetaccess\/","https:\/\/x.com\/buyvpnservice","https:\/\/www.instagram.com\/piavpn\/","https:\/\/www.youtube.com\/channel\/UClyJZ47Rizb1xnwuKXDI0_w"]},{"@type":"Person","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/867d81a36eafaf83e91f6528aca0ba29","name":"PIA Research","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.privateinternetaccess.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/717a02042be28ce22f2ae82923cdaa82551205b8768e3cd4a8fce14988ed0ccd?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/717a02042be28ce22f2ae82923cdaa82551205b8768e3cd4a8fce14988ed0ccd?s=96&d=mm&r=g","caption":"PIA Research"},"sameAs":["https:\/\/www.privateinternetaccess.com"],"url":"https:\/\/www.privateinternetaccess.com\/blog\/author\/piaresearch\/"}]}},"_links":{"self":[{"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/posts\/1938","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/comments?post=1938"}],"version-history":[{"count":14,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/posts\/1938\/revisions"}],"predecessor-version":[{"id":18778,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/posts\/1938\/revisions\/18778"}],"wp:attachment":[{"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/media?parent=1938"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/categories?post=1938"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.privateinternetaccess.com\/blog\/wp-json\/wp\/v2\/tags?post=1938"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}