Netdev List
 help / color / mirror / Atom feed
* [PATCH v15 ] net/veth/XDP: Line-rate packet forwarding in kernel
From: Md. Islam @ 2018-04-02  0:47 UTC (permalink / raw)
  To: netdev, David Miller, David Ahern, stephen, agaceph,
	Pavel Emelyanov, Eric Dumazet, alexei.starovoitov, brouer

[-- Attachment #1: Type: text/plain, Size: 10604 bytes --]

This patch implements IPv4 forwarding on xdp_buff. I added a new
config option XDP_ROUTER. Kernel would forward packets through fast
path when this option is enabled. But it would require driver support.
Currently it only works with veth. Here I have modified veth such that
it outputs xdp_buff. I created a testbed in Mininet. The Mininet
script (topology.py) is attached. Here the topology is:

h1 -----r1-----h2 (r1 acts as a router)

This patch improves the throughput from 53.8Gb/s to 60Gb/s on my
machine. Median RTT also improved from around .055 ms to around .035
ms.

Then I disabled hyperthreading and cpu frequency scaling in order to
utilize CPU cache (DPDK also utilizes CPU cache to improve
forwarding). This further improves per-packet forwarding latency from
around 400ns to 200 ns. More specifically, header parsing and fib
lookup only takes around 82 ns. This shows that this could be used to
implement linerate packet forwarding in kernel.

The patch has been generated on 4.15.0+. Please let me know your
feedback and suggestions. Please feel free to let me know if this
approach make sense.

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 944ec3c..8474eef 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -328,6 +328,18 @@ config VETH
       When one end receives the packet it appears on its pair and vice
       versa.

+config XDP_ROUTER
+    bool "XDP router for veth"
+    depends on IP_ADVANCED_ROUTER
+    depends on VETH
+    default y
+    ---help---
+      This option will enable IP forwarding on incoming xdp_buff.
+      Currently it is only supported by veth. Say y or n.
+
+      Currently veth uses slow path for packet forwarding. This option
+      forwards packets as soon as it is received (as XDP generic).
+
 config VIRTIO_NET
     tristate "Virtio network driver"
     depends on VIRTIO
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index a69ad39..76112f9 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -111,6 +111,29 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb,
struct net_device *dev)
         goto drop;
     }

+#ifdef CONFIG_XDP_ROUTER
+
+    /* if IP forwarding is enabled on the receiver, create xdp_buff
+     * from skb and call xdp_router_forward()
+     */
+    if (is_forwarding_enabled(rcv)) {
+        struct xdp_buff *xdp = kmalloc(sizeof(*xdp), GFP_KERNEL);
+
+        xdp->data = skb->data;
+        xdp->data_end = skb->data + (skb->len - skb->data_len);
+        xdp->data_meta = skb;
+        prefetch_xdp(xdp);
+        if (likely(xdp_router_forward(rcv, xdp) == NET_RX_SUCCESS)) {
+            struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
+
+            u64_stats_update_begin(&stats->syncp);
+            stats->bytes += length;
+            stats->packets++;
+            u64_stats_update_end(&stats->syncp);
+            goto success;
+        }
+    }
+#endif
     if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
         struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);

@@ -122,6 +145,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb,
struct net_device *dev)
 drop:
         atomic64_inc(&priv->dropped);
     }
+success:
     rcu_read_unlock();
     return NETDEV_TX_OK;
 }
@@ -276,6 +300,62 @@ static void veth_set_rx_headroom(struct
net_device *dev, int new_hr)
     rcu_read_unlock();
 }

+#ifdef CONFIG_XDP_ROUTER
+int veth_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
+{
+    struct veth_priv *priv = netdev_priv(dev);
+    struct net_device *rcv;
+    struct ethhdr *ethh;
+    struct sk_buff *skb;
+    int length = xdp->data_end - xdp->data;
+
+    rcu_read_lock();
+    rcv = rcu_dereference(priv->peer);
+    if (unlikely(!rcv)) {
+        kfree(xdp);
+        goto drop;
+    }
+
+    /* Update MAC address and checksum */
+    ethh = eth_hdr_xdp(xdp);
+    ether_addr_copy(ethh->h_source, dev->dev_addr);
+    ether_addr_copy(ethh->h_dest, rcv->dev_addr);
+
+    /* if IP forwarding is enabled on the receiver,
+     * call xdp_router_forward()
+     */
+    if (is_forwarding_enabled(rcv)) {
+        prefetch_xdp(xdp);
+        if (likely(xdp_router_forward(rcv, xdp) == NET_RX_SUCCESS)) {
+            struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
+
+            u64_stats_update_begin(&stats->syncp);
+            stats->bytes += length;
+            stats->packets++;
+            u64_stats_update_end(&stats->syncp);
+            goto success;
+        }
+    }
+
+    /* Local deliver */
+    skb = (struct sk_buff *)xdp->data_meta;
+    if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
+        struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
+
+        u64_stats_update_begin(&stats->syncp);
+        stats->bytes += length;
+        stats->packets++;
+        u64_stats_update_end(&stats->syncp);
+    } else {
+drop:
+        atomic64_inc(&priv->dropped);
+    }
+success:
+    rcu_read_unlock();
+    return NETDEV_TX_OK;
+}
+#endif
+
 static const struct net_device_ops veth_netdev_ops = {
     .ndo_init            = veth_dev_init,
     .ndo_open            = veth_open,
@@ -290,6 +370,9 @@ static const struct net_device_ops veth_netdev_ops = {
     .ndo_get_iflink        = veth_get_iflink,
     .ndo_features_check    = passthru_features_check,
     .ndo_set_rx_headroom    = veth_set_rx_headroom,
+#ifdef CONFIG_XDP_ROUTER
+    .ndo_xdp_xmit        = veth_xdp_xmit,
+#endif
 };

 #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 492bc65..025a3ec 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -19,6 +19,29 @@

 #include <linux/skbuff.h>
 #include <uapi/linux/ip.h>
+#include <linux/filter.h>
+
+#ifdef CONFIG_XDP_ROUTER
+
+#define MIN_PACKET_SIZE 55
+
+static inline struct iphdr *ip_hdr_xdp(const struct xdp_buff *xdp)
+{
+    return (struct iphdr *)(xdp->data+ETH_HLEN);
+}
+
+static inline struct ethhdr *eth_hdr_xdp(const struct xdp_buff *xdp)
+{
+    return (struct ethhdr *)(xdp->data);
+}
+
+static inline bool is_xdp_forwardable(const struct xdp_buff *xdp)
+{
+    return xdp->data_end - xdp->data >= MIN_PACKET_SIZE;
+}
+
+#endif
+

 static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
 {
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4c77f39..e3bf002 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3290,6 +3290,12 @@ static inline void dev_consume_skb_any(struct
sk_buff *skb)
     __dev_kfree_skb_any(skb, SKB_REASON_CONSUMED);
 }

+#ifdef CONFIG_XDP_ROUTER
+bool is_forwarding_enabled(struct net_device *dev);
+int xdp_router_forward(struct net_device *dev, struct xdp_buff *xdp);
+void prefetch_xdp(struct xdp_buff *xdp);
+#endif
+
 void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog);
 int do_xdp_generic(struct bpf_prog *xdp_prog, struct sk_buff *skb);
 int netif_rx(struct sk_buff *skb);
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index f805243..623b2de 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -369,6 +369,12 @@ int fib_sync_down_dev(struct net_device *dev,
unsigned long event, bool force);
 int fib_sync_down_addr(struct net_device *dev, __be32 local);
 int fib_sync_up(struct net_device *dev, unsigned int nh_flags);

+#ifdef CONFIG_XDP_ROUTER
+int ip_route_lookup(__be32 daddr, __be32 saddr,
+                   u8 tos, struct net_device *dev,
+                   struct fib_result *res);
+#endif
+
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
                const struct sk_buff *skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index dda9d7b..9d92352 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4090,6 +4090,65 @@ int do_xdp_generic(struct bpf_prog *xdp_prog,
struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(do_xdp_generic);

+#ifdef CONFIG_XDP_ROUTER
+
+bool is_forwarding_enabled(struct net_device *dev)
+{
+    struct in_device *in_dev;
+
+    /* verify forwarding is enabled on this interface */
+    in_dev = __in_dev_get_rcu(dev);
+    if (unlikely(!in_dev || !IN_DEV_FORWARD(in_dev)))
+        return false;
+
+    return true;
+}
+EXPORT_SYMBOL_GPL(is_forwarding_enabled);
+
+int xdp_router_forward(struct net_device *dev, struct xdp_buff *xdp)
+{
+        int err;
+        struct fib_result res;
+        struct iphdr *iph;
+        struct net_device *rcv;
+
+        if (unlikely(xdp->data_end - xdp->data < MIN_PACKET_SIZE))
+            return NET_RX_DROP;
+
+        iph = (struct iphdr *)(xdp->data + ETH_HLEN);
+
+        /*currently only supports IPv4
+         */
+        if (unlikely(iph->version != 4))
+            return NET_RX_DROP;
+
+        err = ip_route_lookup(iph->daddr, iph->saddr,
+                      iph->tos, dev, &res);
+        if (unlikely(err))
+            return NET_RX_DROP;
+
+        rcv = FIB_RES_DEV(res);
+        if (likely(rcv)) {
+            if (likely(rcv->netdev_ops->ndo_xdp_xmit(rcv, xdp) ==
+                       NETDEV_TX_OK))
+                return NET_RX_SUCCESS;
+        }
+
+        return NET_RX_DROP;
+}
+EXPORT_SYMBOL_GPL(xdp_router_forward);
+
+inline void prefetch_xdp(struct xdp_buff *xdp)
+{
+        prefetch(xdp);
+        /* prefetch version, tos, saddr and daddr of IP header */
+        prefetch(xdp->data + ETH_HLEN);
+        prefetch(xdp->data + ETH_HLEN + 12);
+}
+EXPORT_SYMBOL_GPL(prefetch_xdp);
+
+#endif
+
 static int netif_rx_internal(struct sk_buff *skb)
 {
     int ret;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 49cc1c1..2333205 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1866,6 +1866,35 @@ static int ip_mkroute_input(struct sk_buff *skb,
     return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
 }

+#ifdef CONFIG_XDP_ROUTER
+
+int ip_route_lookup(__be32 daddr, __be32 saddr,
+            u8 tos, struct net_device *dev,
+            struct fib_result *res)
+{
+    struct flowi4    fl4;
+    int        err;
+    struct net    *net = dev_net(dev);
+
+    fl4.flowi4_oif = 0;
+    fl4.flowi4_iif = dev->ifindex;
+    fl4.flowi4_mark = 0;
+    fl4.flowi4_tos = tos & IPTOS_RT_MASK;
+    fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+    fl4.flowi4_flags = 0;
+    fl4.daddr = daddr;
+    fl4.saddr = saddr;
+
+    err = fib_lookup(net, &fl4, res, 0);
+
+    if (unlikely(err != 0 || res->type != RTN_UNICAST))
+        return -EINVAL;
+
+    return 0;
+}
+EXPORT_SYMBOL_GPL(ip_route_lookup);
+#endif
+
 /*
  *    NOTE. We drop all the packets that has local source
  *    addresses, because every properly looped back packet

Many thanks
Tamim

[-- Attachment #2: topology.py --]
[-- Type: text/x-python, Size: 3289 bytes --]

#!/usr/bin/python

"""

##############################################################################
# Topology with one router and two hosts with static routes
#
#       172.16.101.0/24         172.16.102.0/24   
#  h1 ------------------- r1 ------------------ h2
#    .1                .2   .3               .1   
#
##############################################################################

Here r1 acts as a Linux router. There are two veth-pairs in our topology as following.

h1-eth0-------r1-eth2       r1-eth3-----h2eth0    

Packets received on r1-eth2 is being transmitted to r1-eth3 using XDP fast path. Packets are generated on h1 towards h2 using iperf.

"""


from mininet.topo import Topo
from mininet.net import Mininet
from mininet.link import TCLink
from mininet.node import Node, CPULimitedHost
from mininet.log import setLogLevel, info
from mininet.util import custom, waitListening
from mininet.cli import CLI
import sys
import time

class LinuxRouter( Node ):
    "A Node with IP forwarding enabled."

    def config( self, **params ):
        super( LinuxRouter, self).config( **params )
        # Enable forwarding on the router
        self.cmd( 'sysctl net.ipv4.ip_forward=1' )

    def terminate( self ):
        self.cmd( 'sysctl net.ipv4.ip_forward=0' )
        super( LinuxRouter, self ).terminate()

class NetworkTopo( Topo ):
    def build( self, **_opts ):	
        h1 = self.addHost( 'h1', ip='172.16.101.1/24', defaultRoute='via 172.16.101.2' )
        h2 = self.addHost( 'h2', ip='172.16.102.1/24', defaultRoute='via 172.16.102.3' )
	r1 = self.addNode( 'r1', cls=LinuxRouter, ip='172.16.101.2/24' )

        self.addLink( h1, r1, intfName2='r1-eth2', params2={ 'ip' : '172.16.101.2/24' })
        self.addLink( h2, r1, intfName2='r1-eth3', params2={ 'ip' : '172.16.102.3/24' })

def main(cli=0):
    "Test linux router"
    topo = NetworkTopo()

    net = Mininet( topo=topo, controller = None )
    net.start()

#   testing using port 45678, TCP window size 20MB and 10 connection. 
    res = net['h2'].cmd('iperf -s -p 45678 -w 20MB &')
#Anyhing that blocks shouldn't be used in cmd(). Use popen() instead. It will create a new process. Now monitor the output of the process
    proc = net['h1'].popen('iperf -c 172.16.102.1 -p 45678 -t 30  -w 20MB -P 10')


#    print res #Don't uncomment this. Strange things happen :-(

#Parse the res to find out the PID of iperf server. The program can crash if res isn't formatted properly. Try again
    pid = res.split(" ")
    iperf_s_pid = pid[1]
    iperf_c_pid = int(pid[1]) + 1

    print pid[1], int(pid[1]) + 1

#Pin iperf server and client to core 0 and 1 respectively. Note that throughput you get depends on other applications running on a CPU. So if you get bad throughput, try restatring. Even though you close some applications, the process can sit in the backgroud
    net['h2'].cmd('sudo taskset -pc 0 {0}'.format(iperf_s_pid))
    net['h1'].cmd('sudo taskset -pc 1 {0}'.format(iperf_c_pid)) 

    for line in iter(proc.stdout.readline, b''):
	print line

    net['h2'].cmd('sudo kill -9 {0}'.format(iperf_s_pid))
    net['h1'].cmd('sudo kill -9 {0}'.format(iperf_c_pid))

    CLI( net )
    net.stop()

if __name__ == '__main__':
    args = sys.argv
    setLogLevel( 'info' )
    main()

^ permalink raw reply related

* Re: [PATCH v5 04/14] PCI: Add pcie_bandwidth_available() to compute bandwidth available to device
From: Bjorn Helgaas @ 2018-04-02  0:41 UTC (permalink / raw)
  To: Tal Gilboa
  Cc: Tariq Toukan, Jacob Keller, Ariel Elior, Ganesh Goudar,
	Jeff Kirsher, everest-linux-l2, intel-wired-lan, netdev,
	linux-kernel, linux-pci
In-Reply-To: <7b82d160-002f-9687-ad80-5aaff639d7ab@mellanox.com>

On Sun, Apr 01, 2018 at 11:41:42PM +0300, Tal Gilboa wrote:
> On 3/31/2018 12:05 AM, Bjorn Helgaas wrote:
> > From: Tal Gilboa <talgi@mellanox.com>
> > 
> > Add pcie_bandwidth_available() to compute the bandwidth available to a
> > device.  This may be limited by the device itself or by a slower upstream
> > link leading to the device.
> > 
> > The available bandwidth at each link along the path is computed as:
> > 
> >    link_speed * link_width * (1 - encoding_overhead)
> > 
> > The encoding overhead is about 20% for 2.5 and 5.0 GT/s links using 8b/10b
> > encoding, and about 1.5% for 8 GT/s or higher speed links using 128b/130b
> > encoding.
> > 
> > Also return the device with the slowest link and the speed and width of
> > that link.
> > 
> > Signed-off-by: Tal Gilboa <talgi@mellanox.com>
> > [bhelgaas: changelog, leave pcie_get_minimum_link() alone for now, return
> > bw directly, use pci_upstream_bridge(), check "next_bw <= bw" to find
> > uppermost limiting device, return speed/width of the limiting device]
> > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > ---
> >   drivers/pci/pci.c   |   54 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >   include/linux/pci.h |    3 +++
> >   2 files changed, 57 insertions(+)
> > 
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index 9ce89e254197..e00d56b12747 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -5146,6 +5146,60 @@ int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
> >   }
> >   EXPORT_SYMBOL(pcie_get_minimum_link);
> > +/**
> > + * pcie_bandwidth_available - determine minimum link settings of a PCIe
> > + *			      device and its bandwidth limitation
> > + * @dev: PCI device to query
> > + * @limiting_dev: storage for device causing the bandwidth limitation
> > + * @speed: storage for speed of limiting device
> > + * @width: storage for width of limiting device
> > + *
> > + * Walk up the PCI device chain and find the point where the minimum
> > + * bandwidth is available.  Return the bandwidth available there and (if
> > + * limiting_dev, speed, and width pointers are supplied) information about
> > + * that point.
> > + */
> > +u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
> > +			     enum pci_bus_speed *speed,
> > +			     enum pcie_link_width *width)
> > +{
> > +	u16 lnksta;
> > +	enum pci_bus_speed next_speed;
> > +	enum pcie_link_width next_width;
> > +	u32 bw, next_bw;
> > +
> > +	*speed = PCI_SPEED_UNKNOWN;
> > +	*width = PCIE_LNK_WIDTH_UNKNOWN;
> 
> This is not safe anymore, now that we allow speed/width=NULL.

Good catch, thanks!

^ permalink raw reply

* Re: [PATCH v5 03/14] PCI: Add pcie_bandwidth_capable() to compute max supported link bandwidth
From: Bjorn Helgaas @ 2018-04-02  0:40 UTC (permalink / raw)
  To: Tal Gilboa
  Cc: Tariq Toukan, Jacob Keller, Ariel Elior, Ganesh Goudar,
	Jeff Kirsher, everest-linux-l2, intel-wired-lan, netdev,
	linux-kernel, linux-pci
In-Reply-To: <31e66048-e8b8-47ba-baf5-023560b4c124@mellanox.com>

On Sun, Apr 01, 2018 at 11:38:53PM +0300, Tal Gilboa wrote:
> On 3/31/2018 12:05 AM, Bjorn Helgaas wrote:
> > From: Tal Gilboa <talgi@mellanox.com>
> > 
> > Add pcie_bandwidth_capable() to compute the max link bandwidth supported by
> > a device, based on the max link speed and width, adjusted by the encoding
> > overhead.
> > 
> > The maximum bandwidth of the link is computed as:
> > 
> >    max_link_speed * max_link_width * (1 - encoding_overhead)
> > 
> > The encoding overhead is about 20% for 2.5 and 5.0 GT/s links using 8b/10b
> > encoding, and about 1.5% for 8 GT/s or higher speed links using 128b/130b
> > encoding.
> > 
> > Signed-off-by: Tal Gilboa <talgi@mellanox.com>
> > [bhelgaas: adjust for pcie_get_speed_cap() and pcie_get_width_cap()
> > signatures, don't export outside drivers/pci]
> > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > Reviewed-by: Tariq Toukan <tariqt@mellanox.com>
> > ---
> >   drivers/pci/pci.c |   21 +++++++++++++++++++++
> >   drivers/pci/pci.h |    9 +++++++++
> >   2 files changed, 30 insertions(+)
> > 
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index 43075be79388..9ce89e254197 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -5208,6 +5208,27 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev)
> >   	return PCIE_LNK_WIDTH_UNKNOWN;
> >   }
> > +/**
> > + * pcie_bandwidth_capable - calculates a PCI device's link bandwidth capability
> > + * @dev: PCI device
> > + * @speed: storage for link speed
> > + * @width: storage for link width
> > + *
> > + * Calculate a PCI device's link bandwidth by querying for its link speed
> > + * and width, multiplying them, and applying encoding overhead.
> > + */
> > +u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
> > +			   enum pcie_link_width *width)
> > +{
> > +	*speed = pcie_get_speed_cap(dev);
> > +	*width = pcie_get_width_cap(dev);
> > +
> > +	if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
> > +		return 0;
> > +
> > +	return *width * PCIE_SPEED2MBS_ENC(*speed);
> > +}
> > +
> >   /**
> >    * pci_select_bars - Make BAR mask from the type of resource
> >    * @dev: the PCI device for which BAR mask is made
> > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> > index 66738f1050c0..2a50172b9803 100644
> > --- a/drivers/pci/pci.h
> > +++ b/drivers/pci/pci.h
> > @@ -261,8 +261,17 @@ void pci_disable_bridge_window(struct pci_dev *dev);
> >   	 (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
> >   	 "Unknown speed")
> > +/* PCIe speed to Mb/s with encoding overhead: 20% for gen2, ~1.5% for gen3 */
> > +#define PCIE_SPEED2MBS_ENC(speed) \
> 
> Missing gen4.

I made it "gen3+".  I think that's accurate, isn't it?  The spec
doesn't seem to actually use "gen3" as a specific term, but sec 4.2.2
says rates of 8 GT/s or higher (which I think includes gen3 and gen4)
use 128b/130b encoding.

^ permalink raw reply

* Re: [PATCH bpf-next v8 00/11] Landlock LSM: Toward unprivileged sandboxing
From: Tycho Andersen @ 2018-04-02  0:39 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: Andy Lutomirski, LKML, Alexei Starovoitov,
	Arnaldo Carvalho de Melo, Casey Schaufler, Daniel Borkmann,
	David Drysdale, David S . Miller, Eric W . Biederman,
	James Morris, Jann Horn, Jonathan Corbet, Michael Kerrisk,
	Kees Cook, Paul Moore, Sargun Dhillon, Serge E . Hallyn,
	Shuah Khan, Tejun Heo, Thomas Graf, Will Drewry
In-Reply-To: <0f355079-7ee2-c06a-2d47-a7a2fa6d98fe@digikod.net>

Hi Mickaël,

On Mon, Apr 02, 2018 at 12:04:36AM +0200, Mickaël Salaün wrote:
> >> vDSO is a code mapped for all processes. As you said, these processes
> >> may use it or not. What I was thinking about is to use the same concept,
> >> i.e. map a "shim" code into each processes pertaining to a particular
> >> hierarchy (the same way seccomp filters are inherited across processes).
> >> With a seccomp filter matching some syscall (e.g. mount, open), it is
> >> possible to jump back to the shim code thanks to SECCOMP_RET_TRAP. This
> >> shim code should then be able to emulate/patch what is needed, even
> >> faking a file opening by receiving a file descriptor through a UNIX
> >> socket. As did the Chrome sandbox, the seccomp filter may look at the
> >> calling address to allow the shim code to call syscalls without being
> >> catched, if needed. However, relying on SIGSYS may not fit with
> >> arbitrary code. Using a new SECCOMP_RET_EMULATE (?) may be used to jump
> >> to a specific process address, to emulate the syscall in an easier way
> >> than only relying on a {c,e}BPF program.
> >>
> > 
> > This could indeed be done, but I think that Tycho's approach is much
> > cleaner and probably faster.
> > 
> 
> I like it too but how does this handle file descriptors?

I think it could be done fairly simply, the most complicated part is
probably designing an API that doesn't suck. But the basic idea would
be:

struct seccomp_notif_resp {
    __u64 id;
    __s32 error;
    __s64 val;
    __s32 fd;
};

if the handler responds with fd >= 0, we grab the tracer's fd,
duplicate it, and install it somewhere in the tracee's fd table. Since
things like socket() will want to return the fd number as its
installed and the handler doesn't know that, we'll probably want some
way to indicate that the kernel should return this value. We could
either mandate that if fd >= 0, that's the value that will be returned
from the syscall, or add another flag that says "no, install the fd,
but really return what's in val instead).

I guess we can't mandate that we return fd, because e.g. netlink
sockets can sometimes return fds as part of the netlink messages, and
not as the return value from the syscall.

Tycho

^ permalink raw reply

* gretap tunnel redirecting 2 different networks on destination host
From: Marc Roos @ 2018-04-01 17:48 UTC (permalink / raw)
  To: netdev


How can I get the 10.11.12.x traffic received on tun1 at server B to 
eth2? 


I have a server A that sends 172.16.1.x and 10.11.12.x traffic via a 
gretab tunnel 192.168.1.x to server B.

            +-------------+                             +------------+
 172.16.1.x |      B      |                             |      A     |
     -------|eth1         |         192.168.1.x GRETAP  |            |
            |         tun1|-----------------------------|tun1        |
 10.11.12.x |             |                             |            |
     -------|eth2         |                             |            |
            +-------------+                             +------------+

When I put the tun1 interface of server B in a bridge with eth1 I am 
able to ping several 172.16.1.x ip's from server A. And communication on 
this network seems to be ok


- I cannot put eth2 on the same bridge. 
- I thought of creating a 2nd gretab tunnel and use each tunnel for a 
network, but I think there is probably a better solution.

^ permalink raw reply

* gretap tunnel redirecting 2 different networks on destination host
From: Marc Roos @ 2018-04-01 17:48 UTC (permalink / raw)
  To: netdev


How can I get the 10.11.12.x traffic received on tun1 at server B to 
eth2? 


I have a server A that sends 172.16.1.x and 10.11.12.x traffic via a 
gretab tunnel 192.168.1.x to server B.

            +-------------+                             +------------+
 172.16.1.x |      B      |                             |      A     |
     -------|eth1         |         192.168.1.x GRETAP  |            |
            |         tun1|-----------------------------|tun1        |
 10.11.12.x |             |                             |            |
     -------|eth2         |                             |            |
            +-------------+                             +------------+

When I put the tun1 interface of server B in a bridge with eth1 I am 
able to ping several 172.16.1.x ip's from server A. And communication on 
this network seems to be ok


- I cannot put eth2 on the same bridge. 
- I thought of creating a 2nd gretab tunnel and use each tunnel for a 
network, but I think there is probably a better solution.

^ permalink raw reply

* Re: [PATCH] [PATCH] fix typo in command value in drivers/net/phy/mdio-bitbang.
From: Andrew Lunn @ 2018-04-01 23:43 UTC (permalink / raw)
  To: Frans Meulenbroeks; +Cc: netdev, trivial, davem
In-Reply-To: <1522615975-20952-1-git-send-email-fransmeulenbroeks@gmail.com>

On Sun, Apr 01, 2018 at 10:52:55PM +0200, Frans Meulenbroeks wrote:
> mdio-bitbang mentioned 10 for both read and write.
> However mdio read opcode is 10 and write opcode is 01
> Fixed comment.
> 
> Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH bpf-next v8 08/11] landlock: Add ptrace restrictions
From: Mickaël Salaün @ 2018-04-01 22:48 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: LKML, Alexei Starovoitov, Arnaldo Carvalho de Melo,
	Casey Schaufler, Daniel Borkmann, David Drysdale,
	David S . Miller, Eric W . Biederman, James Morris, Jann Horn,
	Jonathan Corbet, Michael Kerrisk, Kees Cook, Paul Moore,
	Sargun Dhillon, Serge E . Hallyn, Shuah Khan, Tejun Heo,
	Thomas Graf, Tycho Andersen, Will Drewry, Kernel 
In-Reply-To: <679089bb-c0ac-ff68-71b1-1813d66c6aa7@digikod.net>


[-- Attachment #1.1: Type: text/plain, Size: 3058 bytes --]


On 03/06/2018 11:28 PM, Mickaël Salaün wrote:
> 
> On 28/02/2018 01:09, Andy Lutomirski wrote:
>> On Wed, Feb 28, 2018 at 12:00 AM, Mickaël Salaün <mic@digikod.net> wrote:
>>>
>>> On 28/02/2018 00:23, Andy Lutomirski wrote:
>>>> On Tue, Feb 27, 2018 at 11:02 PM, Andy Lutomirski <luto@kernel.org> wrote:
>>>>> On Tue, Feb 27, 2018 at 10:14 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>>>>>
>>>>>
>>>>> I think you're wrong here.  Any sane container trying to use Landlock
>>>>> like this would also create a PID namespace.  Problem solved.  I still
>>>>> think you should drop this patch.
>>>
>>> Containers is one use case, another is build-in sandboxing (e.g. for web
>>> browser…) and another one is for sandbox managers (e.g. Firejail,
>>> Bubblewrap, Flatpack…). In some of these use cases, especially from a
>>> developer point of view, you may want/need to debug your applications
>>> (without requiring to be root). For nested Landlock access-controls
>>> (e.g. container + user session + web browser), it may not be allowed to
>>> create a PID namespace, but you still want to have a meaningful
>>> access-control.
>>>
>>
>> The consideration should be exactly the same as for normal seccomp.
>> If I'm in a container (using PID namespaces + seccomp) and a run a web
>> browser, I can debug the browser.
>>
>> If there's a real use case for adding this type of automatic ptrace
>> protection, then by all means, let's add it as a general seccomp
>> feature.
>>
> 
> Right, it makes sense to add this feature to seccomp filters as well.
> What do you think Kees?
> 

As a second though, it may be useful for seccomp but it should be
another patch series, independent from this one.

The idea to keep in mind is that this ptrace restriction is an automatic
way to define what is called a subject in common access control
vocabulary, like used by SELinux. A subject should not be able to
impersonate another one with less restrictions (to get more rights).
Because of the stackable restrictions of Landlock (same principle used
by seccomp), it is easy to identify which subject (i.e. group of
processes) is more restricted (or with different restrictions) than
another. This follow the same principle as Yama's ptrace_scope.

Another important argument for a different ptrace-protection
mechanism than seccomp is that Landlock programs may be applied (i.e.
define subject) otherwise than with a process hierarchy. Another way to
define a Landlock subject may be by using cgroups (which was previously
discussed). I'm also thinking about being able to create (real)
capabilities (not to be confused with POSIX capabilities), which may be
useful to implement some parts of Capsicum, by attaching Landlock
programs to a file descriptor (and not directly to a group of
processes). All this to highlight that the ptrace protection is specific
to Landlock and may not be directly shared with seccomp.

Even if Landlock follows the footprints of seccomp, they are different
beasts.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [PATCH bpf-next v8 00/11] Landlock LSM: Toward unprivileged sandboxing
From: Mickaël Salaün @ 2018-04-01 22:04 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Tycho Andersen, LKML, Alexei Starovoitov,
	Arnaldo Carvalho de Melo, Casey Schaufler, Daniel Borkmann,
	David Drysdale, David S . Miller, Eric W . Biederman,
	James Morris, Jann Horn, Jonathan Corbet, Michael Kerrisk,
	Kees Cook, Paul Moore, Sargun Dhillon, Serge E . Hallyn,
	Shuah Khan, Tejun Heo, Thomas Graf, Will Drewry
In-Reply-To: <CALCETrUwkV4_65y7UjSgrq5WHOcZZ=+znKArehvhb1xEGG9HXw@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 3621 bytes --]


On 03/09/2018 12:53 AM, Andy Lutomirski wrote:
> On Thu, Mar 8, 2018 at 11:51 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>
>> On 07/03/2018 02:21, Andy Lutomirski wrote:
>>> On Tue, Mar 6, 2018 at 11:06 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>>>
>>>> On 06/03/2018 23:46, Tycho Andersen wrote:
>>>>> On Tue, Mar 06, 2018 at 10:33:17PM +0000, Andy Lutomirski wrote:
>>>>>>>> Suppose I'm writing a container manager.  I want to run "mount" in the
>>>>>>>> container, but I don't want to allow moun() in general and I want to
>>>>>>>> emulate certain mount() actions.  I can write a filter that catches
>>>>>>>> mount using seccomp and calls out to the container manager for help.
>>>>>>>> This isn't theoretical -- Tycho wants *exactly* this use case to be
>>>>>>>> supported.
>>>>>>>
>>>>>>> Well, I think this use case should be handled with something like
>>>>>>> LD_PRELOAD and a helper library. FYI, I did something like this:
>>>>>>> https://github.com/stemjail/stemshim
>>>>>>
>>>>>> I doubt that will work for containers.  Containers that use user
>>>>>> namespaces and, for example, setuid programs aren't going to honor
>>>>>> LD_PRELOAD.
>>>>>
>>>>> Or anything that calls syscalls directly, like go programs.
>>>>
>>>> That's why the vDSO-like approach. Enforcing an access control is not
>>>> the issue here, patching a buggy userland (without patching its code) is
>>>> the issue isn't it?
>>>>
>>>> As far as I remember, the main problem is to handle file descriptors
>>>> while "emulating" the kernel behavior. This can be done with a "shim"
>>>> code mapped in every processes. Chrome used something like this (in a
>>>> previous sandbox mechanism) as a kind of emulation (with the current
>>>> seccomp-bpf ). I think it should be doable to replace the (userland)
>>>> emulation code with an IPC wrapper receiving file descriptors through
>>>> UNIX socket.
>>>>
>>>
>>> Can you explain exactly what you mean by "vDSO-like"?
>>>
>>> When a 64-bit program does a syscall, it just executes the SYSCALL
>>> instruction.  The vDSO isn't involved at all.  32-bit programs usually
>>> go through the vDSO, but not always.
>>>
>>> It could be possible to force-load a DSO into an entire container and
>>> rig up seccomp to intercept all SYSCALLs not originating from the DSO
>>> such that they merely redirect control to the DSO, but that seems
>>> quite messy.
>>
>> vDSO is a code mapped for all processes. As you said, these processes
>> may use it or not. What I was thinking about is to use the same concept,
>> i.e. map a "shim" code into each processes pertaining to a particular
>> hierarchy (the same way seccomp filters are inherited across processes).
>> With a seccomp filter matching some syscall (e.g. mount, open), it is
>> possible to jump back to the shim code thanks to SECCOMP_RET_TRAP. This
>> shim code should then be able to emulate/patch what is needed, even
>> faking a file opening by receiving a file descriptor through a UNIX
>> socket. As did the Chrome sandbox, the seccomp filter may look at the
>> calling address to allow the shim code to call syscalls without being
>> catched, if needed. However, relying on SIGSYS may not fit with
>> arbitrary code. Using a new SECCOMP_RET_EMULATE (?) may be used to jump
>> to a specific process address, to emulate the syscall in an easier way
>> than only relying on a {c,e}BPF program.
>>
> 
> This could indeed be done, but I think that Tycho's approach is much
> cleaner and probably faster.
> 

I like it too but how does this handle file descriptors?


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: [PATCH net-next V1 0/4] Introduce adaptive TX interrupt moderation to net DIM
From: David Miller @ 2018-04-01 21:49 UTC (permalink / raw)
  To: talgi; +Cc: netdev, tariqt, saeedm, f.fainelli
In-Reply-To: <1522614497-64957-1-git-send-email-talgi@mellanox.com>

From: Tal Gilboa <talgi@mellanox.com>
Date: Sun,  1 Apr 2018 23:28:13 +0300

> v1: Fix compilation issues due to missed function renaming.

This doesn't even apply cleanly to net-next, always generate your patch
series against the current state of the GIT tree.

Applying: net/dim: Rename *_get_profile() functions to *_get_rx_moderation()
Applying: net/dim: Add "enabled" field to net_dim struct
error: patch failed: drivers/net/ethernet/mellanox/mlx5/core/en_rep.c:881
error: drivers/net/ethernet/mellanox/mlx5/core/en_rep.c: patch does not apply

^ permalink raw reply

* Re: pull request: bluetooth-next 2018-04-01
From: David Miller @ 2018-04-01 21:46 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth, netdev
In-Reply-To: <20180401185342.GA14384@x1c.home>

From: Johan Hedberg <johan.hedberg@gmail.com>
Date: Sun, 1 Apr 2018 21:53:42 +0300

> Here's (most likely) the last bluetooth-next pull request for the 4.17
> kernel:
> 
>  - Remove unused btuart_cs driver (replaced by serial_cs + hci_uart)
>  - New USB ID for Edimax EW-7611ULB controller
>  - Cleanups & fixes to hci_bcm driver
>  - Clenups to btmrvl driver
> 
> Please let me know if there are any issues pulling. Thanks.

Pulled, thanks Johan.

^ permalink raw reply

* Re: [PATCH net] e1000e: Remove Other from EIAC.
From: Jan Kiszka @ 2018-04-01 21:29 UTC (permalink / raw)
  To: Benjamin Poirier, Jeff Kirsher; +Cc: intel-wired-lan, netdev, linux-kernel
In-Reply-To: <20180131072627.18305-1-bpoirier@suse.com>


[-- Attachment #1.1: Type: text/plain, Size: 2533 bytes --]

On 2018-01-31 08:26, Benjamin Poirier wrote:
> It was reported that emulated e1000e devices in vmware esxi 6.5 Build
> 7526125 do not link up after commit 4aea7a5c5e94 ("e1000e: Avoid receiver
> overrun interrupt bursts", v4.15-rc1). Some tracing shows that after
> e1000e_trigger_lsc() is called, ICR reads out as 0x0 in e1000_msix_other()
> on emulated e1000e devices. In comparison, on real e1000e 82574 hardware,
> icr=0x80000004 (_INT_ASSERTED | _LSC) in the same situation.
> 
> Some experimentation showed that this flaw in vmware e1000e emulation can
> be worked around by not setting Other in EIAC. This is how it was before
> 16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt", v4.5-rc1).
> 
> Fixes: 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts")
> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
> ---
>  drivers/net/ethernet/intel/e1000e/netdev.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
> index 9f18d39bdc8f..625a4c9a86a4 100644
> --- a/drivers/net/ethernet/intel/e1000e/netdev.c
> +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
> @@ -1918,6 +1918,8 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
>  	bool enable = true;
>  
>  	icr = er32(ICR);
> +	ew32(ICR, E1000_ICR_OTHER);
> +
>  	if (icr & E1000_ICR_RXO) {
>  		ew32(ICR, E1000_ICR_RXO);
>  		enable = false;
> @@ -2040,7 +2042,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
>  		       hw->hw_addr + E1000_EITR_82574(vector));
>  	else
>  		writel(1, hw->hw_addr + E1000_EITR_82574(vector));
> -	adapter->eiac_mask |= E1000_IMS_OTHER;
>  
>  	/* Cause Tx interrupts on every write back */
>  	ivar |= BIT(31);
> @@ -2265,7 +2266,7 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
>  
>  	if (adapter->msix_entries) {
>  		ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
> -		ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC);
> +		ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
>  	} else if (hw->mac.type >= e1000_pch_lpt) {
>  		ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
>  	} else {
> 

Shouldn't this be queued for stable as well? I'm missing it in 4.14 LTS
at least.

BTW, it seems QEMU's e1000e model is affected by the same issue. I've
proposed a fix for it [1].

Jan

[1] https://www.mail-archive.com/qemu-devel@nongnu.org/msg525182.html


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply

* [PATCH] [PATCH] fix typo in command value in drivers/net/phy/mdio-bitbang.
From: Frans Meulenbroeks @ 2018-04-01 20:52 UTC (permalink / raw)
  Cc: netdev, trivial, davem, Frans Meulenbroeks

mdio-bitbang mentioned 10 for both read and write.
However mdio read opcode is 10 and write opcode is 01
Fixed comment.

Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
---
 drivers/net/phy/mdio-bitbang.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 61a543c..403b085 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -113,7 +113,7 @@ static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)
 	for (i = 0; i < 32; i++)
 		mdiobb_send_bit(ctrl, 1);
 
-	/* send the start bit (01) and the read opcode (10) or write (10).
+	/* send the start bit (01) and the read opcode (10) or write (01).
 	   Clause 45 operation uses 00 for the start and 11, 10 for
 	   read/write */
 	mdiobb_send_bit(ctrl, 0);
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v5 04/14] PCI: Add pcie_bandwidth_available() to compute bandwidth available to device
From: Tal Gilboa @ 2018-04-01 20:41 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Tariq Toukan, Jacob Keller, Ariel Elior, Ganesh Goudar,
	Jeff Kirsher, everest-linux-l2, intel-wired-lan, netdev,
	linux-kernel, linux-pci
In-Reply-To: <152244391143.135666.12548496808512444463.stgit@bhelgaas-glaptop.roam.corp.google.com>

On 3/31/2018 12:05 AM, Bjorn Helgaas wrote:
> From: Tal Gilboa <talgi@mellanox.com>
> 
> Add pcie_bandwidth_available() to compute the bandwidth available to a
> device.  This may be limited by the device itself or by a slower upstream
> link leading to the device.
> 
> The available bandwidth at each link along the path is computed as:
> 
>    link_speed * link_width * (1 - encoding_overhead)
> 
> The encoding overhead is about 20% for 2.5 and 5.0 GT/s links using 8b/10b
> encoding, and about 1.5% for 8 GT/s or higher speed links using 128b/130b
> encoding.
> 
> Also return the device with the slowest link and the speed and width of
> that link.
> 
> Signed-off-by: Tal Gilboa <talgi@mellanox.com>
> [bhelgaas: changelog, leave pcie_get_minimum_link() alone for now, return
> bw directly, use pci_upstream_bridge(), check "next_bw <= bw" to find
> uppermost limiting device, return speed/width of the limiting device]
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
>   drivers/pci/pci.c   |   54 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/pci.h |    3 +++
>   2 files changed, 57 insertions(+)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 9ce89e254197..e00d56b12747 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5146,6 +5146,60 @@ int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
>   }
>   EXPORT_SYMBOL(pcie_get_minimum_link);
>   
> +/**
> + * pcie_bandwidth_available - determine minimum link settings of a PCIe
> + *			      device and its bandwidth limitation
> + * @dev: PCI device to query
> + * @limiting_dev: storage for device causing the bandwidth limitation
> + * @speed: storage for speed of limiting device
> + * @width: storage for width of limiting device
> + *
> + * Walk up the PCI device chain and find the point where the minimum
> + * bandwidth is available.  Return the bandwidth available there and (if
> + * limiting_dev, speed, and width pointers are supplied) information about
> + * that point.
> + */
> +u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
> +			     enum pci_bus_speed *speed,
> +			     enum pcie_link_width *width)
> +{
> +	u16 lnksta;
> +	enum pci_bus_speed next_speed;
> +	enum pcie_link_width next_width;
> +	u32 bw, next_bw;
> +
> +	*speed = PCI_SPEED_UNKNOWN;
> +	*width = PCIE_LNK_WIDTH_UNKNOWN;

This is not safe anymore, now that we allow speed/width=NULL.

> +	bw = 0;
> +
> +	while (dev) {
> +		pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
> +
> +		next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
> +		next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
> +			PCI_EXP_LNKSTA_NLW_SHIFT;
> +
> +		next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
> +
> +		/* Check if current device limits the total bandwidth */
> +		if (!bw || next_bw <= bw) {
> +			bw = next_bw;
> +
> +			if (limiting_dev)
> +				*limiting_dev = dev;
> +			if (speed)
> +				*speed = next_speed;
> +			if (width)
> +				*width = next_width;
> +		}
> +
> +		dev = pci_upstream_bridge(dev);
> +	}
> +
> +	return bw;
> +}
> +EXPORT_SYMBOL(pcie_bandwidth_available);
> +
>   /**
>    * pcie_get_speed_cap - query for the PCI device's link speed capability
>    * @dev: PCI device to query
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 8043a5937ad0..f2bf2b7a66c7 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1083,6 +1083,9 @@ int pcie_get_mps(struct pci_dev *dev);
>   int pcie_set_mps(struct pci_dev *dev, int mps);
>   int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
>   			  enum pcie_link_width *width);
> +u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
> +			     enum pci_bus_speed *speed,
> +			     enum pcie_link_width *width);
>   void pcie_flr(struct pci_dev *dev);
>   int __pci_reset_function_locked(struct pci_dev *dev);
>   int pci_reset_function(struct pci_dev *dev);
> 

^ permalink raw reply

* Re: [PATCH v5 03/14] PCI: Add pcie_bandwidth_capable() to compute max supported link bandwidth
From: Tal Gilboa @ 2018-04-01 20:38 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Tariq Toukan, Jacob Keller, Ariel Elior, Ganesh Goudar,
	Jeff Kirsher, everest-linux-l2, intel-wired-lan, netdev,
	linux-kernel, linux-pci
In-Reply-To: <152244390359.135666.14890735614456271032.stgit@bhelgaas-glaptop.roam.corp.google.com>

On 3/31/2018 12:05 AM, Bjorn Helgaas wrote:
> From: Tal Gilboa <talgi@mellanox.com>
> 
> Add pcie_bandwidth_capable() to compute the max link bandwidth supported by
> a device, based on the max link speed and width, adjusted by the encoding
> overhead.
> 
> The maximum bandwidth of the link is computed as:
> 
>    max_link_speed * max_link_width * (1 - encoding_overhead)
> 
> The encoding overhead is about 20% for 2.5 and 5.0 GT/s links using 8b/10b
> encoding, and about 1.5% for 8 GT/s or higher speed links using 128b/130b
> encoding.
> 
> Signed-off-by: Tal Gilboa <talgi@mellanox.com>
> [bhelgaas: adjust for pcie_get_speed_cap() and pcie_get_width_cap()
> signatures, don't export outside drivers/pci]
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> Reviewed-by: Tariq Toukan <tariqt@mellanox.com>
> ---
>   drivers/pci/pci.c |   21 +++++++++++++++++++++
>   drivers/pci/pci.h |    9 +++++++++
>   2 files changed, 30 insertions(+)
> 
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 43075be79388..9ce89e254197 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -5208,6 +5208,27 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev)
>   	return PCIE_LNK_WIDTH_UNKNOWN;
>   }
>   
> +/**
> + * pcie_bandwidth_capable - calculates a PCI device's link bandwidth capability
> + * @dev: PCI device
> + * @speed: storage for link speed
> + * @width: storage for link width
> + *
> + * Calculate a PCI device's link bandwidth by querying for its link speed
> + * and width, multiplying them, and applying encoding overhead.
> + */
> +u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
> +			   enum pcie_link_width *width)
> +{
> +	*speed = pcie_get_speed_cap(dev);
> +	*width = pcie_get_width_cap(dev);
> +
> +	if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
> +		return 0;
> +
> +	return *width * PCIE_SPEED2MBS_ENC(*speed);
> +}
> +
>   /**
>    * pci_select_bars - Make BAR mask from the type of resource
>    * @dev: the PCI device for which BAR mask is made
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 66738f1050c0..2a50172b9803 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -261,8 +261,17 @@ void pci_disable_bridge_window(struct pci_dev *dev);
>   	 (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
>   	 "Unknown speed")
>   
> +/* PCIe speed to Mb/s with encoding overhead: 20% for gen2, ~1.5% for gen3 */
> +#define PCIE_SPEED2MBS_ENC(speed) \

Missing gen4.

> +	((speed) == PCIE_SPEED_8_0GT ? 7877 : \
> +	 (speed) == PCIE_SPEED_5_0GT ? 4000 : \
> +	 (speed) == PCIE_SPEED_2_5GT ? 2000 : \
> +	 0)
> +
>   enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev);
>   enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev);
> +u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
> +			   enum pcie_link_width *width);
>   
>   /* Single Root I/O Virtualization */
>   struct pci_sriov {
> 

^ permalink raw reply

* Re: [PATCH net-next] net/broadcom: Fixup broken build due to function name change
From: Tal Gilboa @ 2018-04-01 20:29 UTC (permalink / raw)
  To: Florian Fainelli, David S. Miller; +Cc: netdev, Tariq Toukan, Saeed Mahameed
In-Reply-To: <d6730e83-6bc0-d35d-e8db-532bc7597553@gmail.com>

On 4/1/2018 7:33 PM, Florian Fainelli wrote:
> Le 03/31/18 à 23:48, Tal Gilboa a écrit :
>> Fixes: 8c6d6895bebb ("net/dim: Rename *_get_profile() functions to *_get_rx_moderation()")
>> Signed-off-by: Tal Gilboa <talgi@mellanox.com>
> 
> I think David just backed out your entire patch series adding TX DIM so
> you would have to incorporate that change into your series and
> re-submit. Thanks!
> 
I see. Re-submitted the original series with a fix.
Please ignore this patch.

^ permalink raw reply

* [PATCH net-next V1 2/4] net/dim: Add "enabled" field to net_dim struct
From: Tal Gilboa @ 2018-04-01 20:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Tariq Toukan, Tal Gilboa, Saeed Mahameed,
	Florian Fainelli
In-Reply-To: <1522614497-64957-1-git-send-email-talgi@mellanox.com>

Preparation for introducing adaptive TX to net DIM.

Signed-off-by: Tal Gilboa <talgi@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h         |  1 -
 drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 10 +++++++---
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c    |  6 +++---
 drivers/net/ethernet/mellanox/mlx5/core/en_rep.c     |  2 +-
 include/linux/net_dim.h                              |  2 ++
 5 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 0c2fdf0..3e24864 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -250,7 +250,6 @@ struct mlx5e_params {
 	u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE];
 	bool vlan_strip_disable;
 	bool scatter_fcs_en;
-	bool rx_dim_enabled;
 	u32 lro_timeout;
 	u32 pflags;
 	struct bpf_prog *xdp_prog;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index c57c929..4b5d022 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -459,9 +459,10 @@ int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
 
 	coal->rx_coalesce_usecs       = priv->channels.params.rx_cq_moderation.usec;
 	coal->rx_max_coalesced_frames = priv->channels.params.rx_cq_moderation.pkts;
+	coal->use_adaptive_rx_coalesce =
+		priv->channels.params.rx_cq_moderation.enabled;
 	coal->tx_coalesce_usecs       = priv->channels.params.tx_cq_moderation.usec;
 	coal->tx_max_coalesced_frames = priv->channels.params.tx_cq_moderation.pkts;
-	coal->use_adaptive_rx_coalesce = priv->channels.params.rx_dim_enabled;
 
 	return 0;
 }
@@ -515,7 +516,8 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 	new_channels.params.tx_cq_moderation.pkts = coal->tx_max_coalesced_frames;
 	new_channels.params.rx_cq_moderation.usec = coal->rx_coalesce_usecs;
 	new_channels.params.rx_cq_moderation.pkts = coal->rx_max_coalesced_frames;
-	new_channels.params.rx_dim_enabled        = !!coal->use_adaptive_rx_coalesce;
+	new_channels.params.rx_cq_moderation.enabled =
+		!!coal->use_adaptive_rx_coalesce;
 
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
 		priv->channels.params = new_channels.params;
@@ -523,7 +525,9 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 	}
 	/* we are opened */
 
-	reset = !!coal->use_adaptive_rx_coalesce != priv->channels.params.rx_dim_enabled;
+	reset = !!coal->use_adaptive_rx_coalesce !=
+			priv->channels.params.rx_cq_moderation.enabled;
+
 	if (!reset) {
 		mlx5e_set_priv_channels_coalesce(priv, coal);
 		priv->channels.params = new_channels.params;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 8a9670c..e16a705 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -781,7 +781,7 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
 	if (err)
 		goto err_destroy_rq;
 
-	if (params->rx_dim_enabled)
+	if (params->rx_cq_moderation.enabled)
 		c->rq.state |= BIT(MLX5E_RQ_STATE_AM);
 
 	return 0;
@@ -4083,7 +4083,7 @@ void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
 		params->rx_cq_moderation.usec =
 			MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE;
 
-	if (params->rx_dim_enabled) {
+	if (params->rx_cq_moderation.enabled) {
 		switch (cq_period_mode) {
 		case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
 			params->rx_cq_moderation =
@@ -4155,7 +4155,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
 	cq_period_mode = MLX5_CAP_GEN(mdev, cq_period_start_from_cqe) ?
 			MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
 			MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
-	params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
+	params->rx_cq_moderation.enabled = MLX5_CAP_GEN(mdev, cq_moderation);
 	mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
 	mlx5e_set_tx_cq_mode_params(params, cq_period_mode);
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index dd32f3e..f238d4c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -881,7 +881,7 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev,
 	params->rq_wq_type  = MLX5_WQ_TYPE_LINKED_LIST;
 	params->log_rq_size = MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE;
 
-	params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
+	params->rx_cq_moderation.enabled = MLX5_CAP_GEN(mdev, cq_moderation);
 	mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
 
 	params->num_tc                = 1;
diff --git a/include/linux/net_dim.h b/include/linux/net_dim.h
index e1cabaf..d34fbfe 100644
--- a/include/linux/net_dim.h
+++ b/include/linux/net_dim.h
@@ -40,6 +40,7 @@ struct net_dim_cq_moder {
 	u16 usec;
 	u16 pkts;
 	u8 cq_period_mode;
+	bool enabled;
 };
 
 struct net_dim_sample {
@@ -135,6 +136,7 @@ enum {
 	struct net_dim_cq_moder cq_moder = profile[cq_period_mode][ix];
 
 	cq_moder.cq_period_mode = cq_period_mode;
+	cq_moder.enabled = true;
 	return cq_moder;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net-next V1 3/4] net/dim: Support adaptive TX moderation
From: Tal Gilboa @ 2018-04-01 20:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Tariq Toukan, Tal Gilboa, Saeed Mahameed,
	Florian Fainelli
In-Reply-To: <1522614497-64957-1-git-send-email-talgi@mellanox.com>

Interrupt moderation for TX traffic requires different profiles than RX
interrupt moderation. The main goal here is to reduce interrupt rate and
allow better payload aggregation by keeping SKBs in the TX queue a bit
longer. Ping-pong behavior would get a profile with a short timer, so
latency wouldn't increase for these scenarios. There's a slight degradtion
in bandwidth for single stream with large message sizes, since
net.ipv4.tcp_limit_output_bytes is limiting the allowed TX traffic, but
with many streams performance is always improved.

Performance improvements (ConnectX-5 100GbE)
Bandwidth: increased up to 40% (1024B with 10s of streams).
Interrupt rate: reduced up to 50% (1024B with 1000s of streams).

Performance degradation (ConnectX-5 100GbE)
Bandwidth: up to 10% decrease single stream TCP (1MB message size from
51Gb/s to 47Gb/s).

*Both cases with TX EQE based moderation enabled.

Signed-off-by: Tal Gilboa <talgi@mellanox.com>
---
 include/linux/net_dim.h | 64 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 13 deletions(-)

diff --git a/include/linux/net_dim.h b/include/linux/net_dim.h
index d34fbfe..9449a61 100644
--- a/include/linux/net_dim.h
+++ b/include/linux/net_dim.h
@@ -104,11 +104,12 @@ enum {
 #define NET_DIM_PARAMS_NUM_PROFILES 5
 /* Adaptive moderation profiles */
 #define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
+#define NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE 128
 #define NET_DIM_DEF_PROFILE_CQE 1
 #define NET_DIM_DEF_PROFILE_EQE 1
 
 /* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
-#define NET_DIM_EQE_PROFILES { \
+#define NET_DIM_RX_EQE_PROFILES { \
 	{1,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
 	{8,   NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
 	{64,  NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
@@ -116,7 +117,7 @@ enum {
 	{256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
 }
 
-#define NET_DIM_CQE_PROFILES { \
+#define NET_DIM_RX_CQE_PROFILES { \
 	{2,  256},             \
 	{8,  128},             \
 	{16, 64},              \
@@ -124,16 +125,38 @@ enum {
 	{64, 64}               \
 }
 
+#define NET_DIM_TX_EQE_PROFILES { \
+	{1,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{8,   NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{32,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{64,  NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE},  \
+	{128, NET_DIM_DEFAULT_TX_CQ_MODERATION_PKTS_FROM_EQE}   \
+}
+
+#define NET_DIM_TX_CQE_PROFILES { \
+	{5,  128},  \
+	{8,  64},  \
+	{16, 32},  \
+	{32, 32},  \
+	{64, 32}   \
+}
+
+static const struct net_dim_cq_moder
+rx_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+	NET_DIM_RX_EQE_PROFILES,
+	NET_DIM_RX_CQE_PROFILES,
+};
+
 static const struct net_dim_cq_moder
-profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
-	NET_DIM_EQE_PROFILES,
-	NET_DIM_CQE_PROFILES,
+tx_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+	NET_DIM_TX_EQE_PROFILES,
+	NET_DIM_TX_CQE_PROFILES,
 };
 
 static inline struct net_dim_cq_moder
 net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
 {
-	struct net_dim_cq_moder cq_moder = profile[cq_period_mode][ix];
+	struct net_dim_cq_moder cq_moder = rx_profile[cq_period_mode][ix];
 
 	cq_moder.cq_period_mode = cq_period_mode;
 	cq_moder.enabled = true;
@@ -141,16 +164,31 @@ enum {
 }
 
 static inline struct net_dim_cq_moder
-net_dim_get_def_rx_moderation(u8 rx_cq_period_mode)
+net_dim_get_def_rx_moderation(u8 cq_period_mode)
 {
-	int default_profile_ix;
+	u8 profile_ix = cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+			NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
 
-	if (rx_cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE)
-		default_profile_ix = NET_DIM_DEF_PROFILE_CQE;
-	else /* NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE */
-		default_profile_ix = NET_DIM_DEF_PROFILE_EQE;
+	return net_dim_get_rx_moderation(cq_period_mode, profile_ix);
+}
+
+static inline struct net_dim_cq_moder
+net_dim_get_tx_moderation(u8 cq_period_mode, int ix)
+{
+	struct net_dim_cq_moder cq_moder = tx_profile[cq_period_mode][ix];
+
+	cq_moder.cq_period_mode = cq_period_mode;
+	cq_moder.enabled = true;
+	return cq_moder;
+}
+
+static inline struct net_dim_cq_moder
+net_dim_get_def_tx_moderation(u8 cq_period_mode)
+{
+	u8 profile_ix = cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+			NET_DIM_DEF_PROFILE_CQE : NET_DIM_DEF_PROFILE_EQE;
 
-	return net_dim_get_rx_moderation(rx_cq_period_mode, default_profile_ix);
+	return net_dim_get_tx_moderation(cq_period_mode, profile_ix);
 }
 
 static inline bool net_dim_on_top(struct net_dim *dim)
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net-next V1 4/4] net/mlx5e: Enable adaptive-TX moderation
From: Tal Gilboa @ 2018-04-01 20:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Tariq Toukan, Tal Gilboa, Saeed Mahameed,
	Florian Fainelli
In-Reply-To: <1522614497-64957-1-git-send-email-talgi@mellanox.com>

Add support for adaptive TX moderation. This greatly reduces TX interrupt
rate and increases bandwidth, mostly for TCP bandwidth over ARM
architecture (below). There is a slight single stream TCP with very large
message sizes degradation (x86). In this case if there's any moderation on
transmitted packets the bandwidth would reduce due to hitting TCP output
limit. Since this is a synthetic case, this is still worth doing.

Performance improvement (ConnectX-4Lx 40GbE, ARM)
TCP 64B bandwidth with 1-50 streams increased 6-35%.
TCP 64B bandwidth with 100-500 streams increased 20-70%.

Performance improvement (ConnectX-5 100GbE, x86)
Bandwidth: increased up to 40% (1024B with 10s of streams).
Interrupt rate: reduced up to 50% (1024B with 1000s of streams).

Signed-off-by: Tal Gilboa <talgi@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |  4 +++
 drivers/net/ethernet/mellanox/mlx5/core/en_dim.c   | 24 +++++++++++---
 .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   | 37 ++++++++++++++--------
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  | 22 +++++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c  | 37 ++++++++++++++++------
 5 files changed, 96 insertions(+), 28 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 3e24864..e18574d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -338,6 +338,7 @@ enum {
 	MLX5E_SQ_STATE_IPSEC,
 	MLX5E_SQ_STATE_TLS,
 	MLX5E_SQ_STATE_RECOVERING,
+	MLX5E_SQ_STATE_AM,
 };
 
 struct mlx5e_sq_wqe_info {
@@ -350,6 +351,7 @@ struct mlx5e_txqsq {
 	/* dirtied @completion */
 	u16                        cc;
 	u32                        dma_fifo_cc;
+	struct net_dim             dim; /* Adaptive Moderation */
 
 	/* dirtied @xmit */
 	u16                        pc ____cacheline_aligned_in_smp;
@@ -387,6 +389,7 @@ struct mlx5e_txqsq {
 		struct work_struct         recover_work;
 		u64                        last_recover;
 	} recover;
+
 } ____cacheline_aligned_in_smp;
 
 struct mlx5e_xdpsq {
@@ -1136,4 +1139,5 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
 			    u16 max_channels);
 u8 mlx5e_params_calculate_tx_min_inline(struct mlx5_core_dev *mdev);
 void mlx5e_rx_dim_work(struct work_struct *work);
+void mlx5e_tx_dim_work(struct work_struct *work);
 #endif /* __MLX5_EN_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
index 1b286e1..9cec351 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
@@ -33,16 +33,30 @@
 #include <linux/net_dim.h>
 #include "en.h"
 
+static inline void
+mlx5e_complete_dim_work(struct net_dim *dim, struct net_dim_cq_moder moder,
+			struct mlx5_core_dev *mdev, struct mlx5_core_cq *mcq)
+{
+	mlx5_core_modify_cq_moderation(mdev, mcq, moder.usec, moder.pkts);
+	dim->state = NET_DIM_START_MEASURE;
+}
+
 void mlx5e_rx_dim_work(struct work_struct *work)
 {
-	struct net_dim *dim = container_of(work, struct net_dim,
-					   work);
+	struct net_dim *dim = container_of(work, struct net_dim, work);
 	struct mlx5e_rq *rq = container_of(dim, struct mlx5e_rq, dim);
 	struct net_dim_cq_moder cur_moder =
 		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 
-	mlx5_core_modify_cq_moderation(rq->mdev, &rq->cq.mcq,
-				       cur_moder.usec, cur_moder.pkts);
+	mlx5e_complete_dim_work(dim, cur_moder, rq->mdev, &rq->cq.mcq);
+}
 
-	dim->state = NET_DIM_START_MEASURE;
+void mlx5e_tx_dim_work(struct work_struct *work)
+{
+	struct net_dim *dim = container_of(work, struct net_dim, work);
+	struct mlx5e_txqsq *sq = container_of(dim, struct mlx5e_txqsq, dim);
+	struct net_dim_cq_moder cur_moder =
+		net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
+
+	mlx5e_complete_dim_work(dim, cur_moder, sq->cq.mdev, &sq->cq.mcq);
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 4b5d022..05faaf7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -454,15 +454,20 @@ static int mlx5e_set_channels(struct net_device *dev,
 int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
 			       struct ethtool_coalesce *coal)
 {
+	struct net_dim_cq_moder *rx_moder, *tx_moder;
+
 	if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
 		return -EOPNOTSUPP;
 
-	coal->rx_coalesce_usecs       = priv->channels.params.rx_cq_moderation.usec;
-	coal->rx_max_coalesced_frames = priv->channels.params.rx_cq_moderation.pkts;
-	coal->use_adaptive_rx_coalesce =
-		priv->channels.params.rx_cq_moderation.enabled;
-	coal->tx_coalesce_usecs       = priv->channels.params.tx_cq_moderation.usec;
-	coal->tx_max_coalesced_frames = priv->channels.params.tx_cq_moderation.pkts;
+	rx_moder = &priv->channels.params.rx_cq_moderation;
+	coal->rx_coalesce_usecs		= rx_moder->usec;
+	coal->rx_max_coalesced_frames	= rx_moder->pkts;
+	coal->use_adaptive_rx_coalesce	= rx_moder->enabled;
+
+	tx_moder = &priv->channels.params.tx_cq_moderation;
+	coal->tx_coalesce_usecs		= tx_moder->usec;
+	coal->tx_max_coalesced_frames	= tx_moder->pkts;
+	coal->use_adaptive_tx_coalesce	= tx_moder->enabled;
 
 	return 0;
 }
@@ -501,6 +506,7 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
 int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 			       struct ethtool_coalesce *coal)
 {
+	struct net_dim_cq_moder *rx_moder, *tx_moder;
 	struct mlx5_core_dev *mdev = priv->mdev;
 	struct mlx5e_channels new_channels = {};
 	int err = 0;
@@ -512,12 +518,15 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 	mutex_lock(&priv->state_lock);
 	new_channels.params = priv->channels.params;
 
-	new_channels.params.tx_cq_moderation.usec = coal->tx_coalesce_usecs;
-	new_channels.params.tx_cq_moderation.pkts = coal->tx_max_coalesced_frames;
-	new_channels.params.rx_cq_moderation.usec = coal->rx_coalesce_usecs;
-	new_channels.params.rx_cq_moderation.pkts = coal->rx_max_coalesced_frames;
-	new_channels.params.rx_cq_moderation.enabled =
-		!!coal->use_adaptive_rx_coalesce;
+	rx_moder          = &new_channels.params.rx_cq_moderation;
+	rx_moder->usec    = coal->rx_coalesce_usecs;
+	rx_moder->pkts    = coal->rx_max_coalesced_frames;
+	rx_moder->enabled = !!coal->use_adaptive_rx_coalesce;
+
+	tx_moder          = &new_channels.params.tx_cq_moderation;
+	tx_moder->usec    = coal->tx_coalesce_usecs;
+	tx_moder->pkts    = coal->tx_max_coalesced_frames;
+	tx_moder->enabled = !!coal->use_adaptive_tx_coalesce;
 
 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
 		priv->channels.params = new_channels.params;
@@ -525,8 +534,8 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 	}
 	/* we are opened */
 
-	reset = !!coal->use_adaptive_rx_coalesce !=
-			priv->channels.params.rx_cq_moderation.enabled;
+	reset = (!!rx_moder->enabled != priv->channels.params.rx_cq_moderation.enabled) ||
+		(!!tx_moder->enabled != priv->channels.params.tx_cq_moderation.enabled);
 
 	if (!reset) {
 		mlx5e_set_priv_channels_coalesce(priv, coal);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index e16a705..651f029 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -993,6 +993,9 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
 	if (err)
 		goto err_sq_wq_destroy;
 
+	INIT_WORK(&sq->dim.work, mlx5e_tx_dim_work);
+	sq->dim.mode = params->tx_cq_moderation.cq_period_mode;
+
 	sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS;
 
 	return 0;
@@ -1156,6 +1159,9 @@ static int mlx5e_open_txqsq(struct mlx5e_channel *c,
 	if (tx_rate)
 		mlx5e_set_sq_maxrate(c->netdev, sq, tx_rate);
 
+	if (params->tx_cq_moderation.enabled)
+		sq->state |= BIT(MLX5E_SQ_STATE_AM);
+
 	return 0;
 
 err_free_txqsq:
@@ -4065,6 +4071,21 @@ void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
 		params->tx_cq_moderation.usec =
 			MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC_FROM_CQE;
 
+	if (params->tx_cq_moderation.enabled) {
+		switch (cq_period_mode) {
+		case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
+			params->tx_cq_moderation =
+				net_dim_get_def_tx_moderation(
+					NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE);
+			break;
+		case MLX5_CQ_PERIOD_MODE_START_FROM_EQE:
+		default:
+			params->tx_cq_moderation =
+				net_dim_get_def_tx_moderation(
+					NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE);
+		}
+	}
+
 	MLX5E_SET_PFLAG(params, MLX5E_PFLAG_TX_CQE_BASED_MODER,
 			params->tx_cq_moderation.cq_period_mode ==
 				MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
@@ -4156,6 +4177,7 @@ void mlx5e_build_nic_params(struct mlx5_core_dev *mdev,
 			MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
 			MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
 	params->rx_cq_moderation.enabled = MLX5_CAP_GEN(mdev, cq_moderation);
+	params->tx_cq_moderation.enabled = params->rx_cq_moderation.enabled;
 	mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
 	mlx5e_set_tx_cq_mode_params(params, cq_period_mode);
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
index f292bb3..ff1d5fe 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
@@ -44,6 +44,30 @@ static inline bool mlx5e_channel_no_affinity_change(struct mlx5e_channel *c)
 	return cpumask_test_cpu(current_cpu, aff);
 }
 
+static inline void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
+{
+	struct net_dim_sample dim_sample;
+
+	if (unlikely(!MLX5E_TEST_BIT(sq->state, MLX5E_SQ_STATE_AM)))
+		return;
+
+	net_dim_sample(sq->cq.event_ctr, sq->stats.packets, sq->stats.bytes,
+		       &dim_sample);
+	net_dim(&sq->dim, dim_sample);
+}
+
+static inline void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
+{
+	struct net_dim_sample dim_sample;
+
+	if (unlikely(!MLX5E_TEST_BIT(rq->state, MLX5E_RQ_STATE_AM)))
+		return;
+
+	net_dim_sample(rq->cq.event_ctr, rq->stats.packets, rq->stats.bytes,
+		       &dim_sample);
+	net_dim(&rq->dim, dim_sample);
+}
+
 int mlx5e_napi_poll(struct napi_struct *napi, int budget)
 {
 	struct mlx5e_channel *c = container_of(napi, struct mlx5e_channel,
@@ -75,18 +99,13 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
 	if (unlikely(!napi_complete_done(napi, work_done)))
 		return work_done;
 
-	for (i = 0; i < c->num_tc; i++)
+	for (i = 0; i < c->num_tc; i++) {
+		mlx5e_handle_tx_dim(&c->sq[i]);
 		mlx5e_cq_arm(&c->sq[i].cq);
-
-	if (MLX5E_TEST_BIT(c->rq.state, MLX5E_RQ_STATE_AM)) {
-		struct net_dim_sample dim_sample;
-		net_dim_sample(c->rq.cq.event_ctr,
-			       c->rq.stats.packets,
-			       c->rq.stats.bytes,
-			       &dim_sample);
-		net_dim(&c->rq.dim, dim_sample);
 	}
 
+	mlx5e_handle_rx_dim(&c->rq);
+
 	mlx5e_cq_arm(&c->rq.cq);
 	mlx5e_cq_arm(&c->icosq.cq);
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net-next V1 0/4] Introduce adaptive TX interrupt moderation to net DIM
From: Tal Gilboa @ 2018-04-01 20:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Tariq Toukan, Tal Gilboa, Saeed Mahameed,
	Florian Fainelli

Net DIM is a library designed for dynamic interrupt moderation. It was
implemented and optimized with receive side interrupts in mind, since these
are usually the CPU expensive ones. This patch-set introduces adaptive transmit
interrupt moderation to net DIM, complete with a usage in the mlx5e driver.
Using adaptive TX behavior would reduce interrupt rate for multiple scenarios.
Furthermore, it is essential for increasing bandwidth on cases where payload
aggregation is required.

In order to avoid conflicts, this patch-set is rebased over Florian Fainelli's
"[PATCH net-next v2 3/3] net: bcmgenet: Fix coalescing settings handling" patch.

v1: Fix compilation issues due to missed function renaming.

Tal Gilboa (4):
  net/dim: Rename *_get_profile() functions to *_get_rx_moderation()
  net/dim: Add "enabled" field to net_dim struct
  net/dim: Support adaptive TX moderation
  net/mlx5e: Enable adaptive-TX moderation

 drivers/net/ethernet/broadcom/bcmsysport.c         |  6 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c      |  8 +--
 drivers/net/ethernet/broadcom/genet/bcmgenet.c     |  6 +-
 drivers/net/ethernet/mellanox/mlx5/core/en.h       |  5 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_dim.c   | 28 ++++++---
 .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   | 35 +++++++----
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  | 34 ++++++++--
 drivers/net/ethernet/mellanox/mlx5/core/en_rep.c   |  2 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c  | 37 ++++++++---
 include/linux/net_dim.h                            | 72 +++++++++++++++++-----
 10 files changed, 173 insertions(+), 60 deletions(-)

-- 
1.8.3.1

^ permalink raw reply

* [PATCH net-next V1 1/4] net/dim: Rename *_get_profile() functions to *_get_rx_moderation()
From: Tal Gilboa @ 2018-04-01 20:28 UTC (permalink / raw)
  To: David S. Miller
  Cc: netdev, Tariq Toukan, Tal Gilboa, Saeed Mahameed,
	Florian Fainelli
In-Reply-To: <1522614497-64957-1-git-send-email-talgi@mellanox.com>

Preparation for introducing adaptive TX to net DIM.

Signed-off-by: Tal Gilboa <talgi@mellanox.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c        |  6 +++---
 drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c     |  8 ++++----
 drivers/net/ethernet/broadcom/genet/bcmgenet.c    |  6 +++---
 drivers/net/ethernet/mellanox/mlx5/core/en_dim.c  |  6 +++---
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c |  6 ++++--
 include/linux/net_dim.h                           | 12 ++++++------
 6 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 4a75b1d..98c5183 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -654,7 +654,7 @@ static int bcm_sysport_set_coalesce(struct net_device *dev,
 	pkts = priv->rx_max_coalesced_frames;
 
 	if (ec->use_adaptive_rx_coalesce && !priv->dim.use_dim) {
-		moder = net_dim_get_def_profile(priv->dim.dim.mode);
+		moder = net_dim_get_def_rx_moderation(priv->dim.dim.mode);
 		usecs = moder.usec;
 		pkts = moder.pkts;
 	}
@@ -1064,7 +1064,7 @@ static void bcm_sysport_dim_work(struct work_struct *work)
 	struct bcm_sysport_priv *priv =
 			container_of(ndim, struct bcm_sysport_priv, dim);
 	struct net_dim_cq_moder cur_profile =
-				net_dim_get_profile(dim->mode, dim->profile_ix);
+				net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 
 	bcm_sysport_set_rx_coalesce(priv, cur_profile.usec, cur_profile.pkts);
 	dim->state = NET_DIM_START_MEASURE;
@@ -1436,7 +1436,7 @@ static void bcm_sysport_init_rx_coalesce(struct bcm_sysport_priv *priv)
 
 	/* If DIM was enabled, re-apply default parameters */
 	if (dim->use_dim) {
-		moder = net_dim_get_def_profile(dim->dim.mode);
+		moder = net_dim_get_def_rx_moderation(dim->dim.mode);
 		usecs = moder.usec;
 		pkts = moder.pkts;
 	}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
index 408dd19..afa97c8 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dim.c
@@ -21,11 +21,11 @@ void bnxt_dim_work(struct work_struct *work)
 	struct bnxt_napi *bnapi = container_of(cpr,
 					       struct bnxt_napi,
 					       cp_ring);
-	struct net_dim_cq_moder cur_profile = net_dim_get_profile(dim->mode,
-								  dim->profile_ix);
+	struct net_dim_cq_moder cur_moder =
+		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 
-	cpr->rx_ring_coal.coal_ticks = cur_profile.usec;
-	cpr->rx_ring_coal.coal_bufs = cur_profile.pkts;
+	cpr->rx_ring_coal.coal_ticks = cur_moder.usec;
+	cpr->rx_ring_coal.coal_bufs = cur_moder.pkts;
 
 	bnxt_hwrm_set_ring_coal(bnapi->bp, bnapi);
 	dim->state = NET_DIM_START_MEASURE;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index f8af472..ccd9205 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -652,7 +652,7 @@ static void bcmgenet_set_ring_rx_coalesce(struct bcmgenet_rx_ring *ring,
 	pkts = ring->rx_max_coalesced_frames;
 
 	if (ec->use_adaptive_rx_coalesce && !ring->dim.use_dim) {
-		moder = net_dim_get_def_profile(ring->dim.dim.mode);
+		moder = net_dim_get_def_rx_moderation(ring->dim.dim.mode);
 		usecs = moder.usec;
 		pkts = moder.pkts;
 	}
@@ -1924,7 +1924,7 @@ static void bcmgenet_dim_work(struct work_struct *work)
 	struct bcmgenet_rx_ring *ring =
 			container_of(ndim, struct bcmgenet_rx_ring, dim);
 	struct net_dim_cq_moder cur_profile =
-			net_dim_get_profile(dim->mode, dim->profile_ix);
+			net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 
 	bcmgenet_set_rx_coalesce(ring, cur_profile.usec, cur_profile.pkts);
 	dim->state = NET_DIM_START_MEASURE;
@@ -2101,7 +2101,7 @@ static void bcmgenet_init_rx_coalesce(struct bcmgenet_rx_ring *ring)
 
 	/* If DIM was enabled, re-apply default parameters */
 	if (dim->use_dim) {
-		moder = net_dim_get_def_profile(dim->dim.mode);
+		moder = net_dim_get_def_rx_moderation(dim->dim.mode);
 		usecs = moder.usec;
 		pkts = moder.pkts;
 	}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
index 602851a..1b286e1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dim.c
@@ -38,11 +38,11 @@ void mlx5e_rx_dim_work(struct work_struct *work)
 	struct net_dim *dim = container_of(work, struct net_dim,
 					   work);
 	struct mlx5e_rq *rq = container_of(dim, struct mlx5e_rq, dim);
-	struct net_dim_cq_moder cur_profile = net_dim_get_profile(dim->mode,
-								  dim->profile_ix);
+	struct net_dim_cq_moder cur_moder =
+		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
 
 	mlx5_core_modify_cq_moderation(rq->mdev, &rq->cq.mcq,
-				       cur_profile.usec, cur_profile.pkts);
+				       cur_moder.usec, cur_moder.pkts);
 
 	dim->state = NET_DIM_START_MEASURE;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 4a675f1..8a9670c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -4087,12 +4087,14 @@ void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
 		switch (cq_period_mode) {
 		case MLX5_CQ_PERIOD_MODE_START_FROM_CQE:
 			params->rx_cq_moderation =
-				net_dim_get_def_profile(NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE);
+				net_dim_get_def_rx_moderation(
+					NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE);
 			break;
 		case MLX5_CQ_PERIOD_MODE_START_FROM_EQE:
 		default:
 			params->rx_cq_moderation =
-				net_dim_get_def_profile(NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE);
+				net_dim_get_def_rx_moderation(
+					NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE);
 		}
 	}
 
diff --git a/include/linux/net_dim.h b/include/linux/net_dim.h
index bebeaad..e1cabaf 100644
--- a/include/linux/net_dim.h
+++ b/include/linux/net_dim.h
@@ -129,17 +129,17 @@ enum {
 	NET_DIM_CQE_PROFILES,
 };
 
-static inline struct net_dim_cq_moder net_dim_get_profile(u8 cq_period_mode,
-							  int ix)
+static inline struct net_dim_cq_moder
+net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
 {
-	struct net_dim_cq_moder cq_moder;
+	struct net_dim_cq_moder cq_moder = profile[cq_period_mode][ix];
 
-	cq_moder = profile[cq_period_mode][ix];
 	cq_moder.cq_period_mode = cq_period_mode;
 	return cq_moder;
 }
 
-static inline struct net_dim_cq_moder net_dim_get_def_profile(u8 rx_cq_period_mode)
+static inline struct net_dim_cq_moder
+net_dim_get_def_rx_moderation(u8 rx_cq_period_mode)
 {
 	int default_profile_ix;
 
@@ -148,7 +148,7 @@ static inline struct net_dim_cq_moder net_dim_get_def_profile(u8 rx_cq_period_mo
 	else /* NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE */
 		default_profile_ix = NET_DIM_DEF_PROFILE_EQE;
 
-	return net_dim_get_profile(rx_cq_period_mode, default_profile_ix);
+	return net_dim_get_rx_moderation(rx_cq_period_mode, default_profile_ix);
 }
 
 static inline bool net_dim_on_top(struct net_dim *dim)
-- 
1.8.3.1

^ permalink raw reply related

* pull request: bluetooth-next 2018-04-01
From: Johan Hedberg @ 2018-04-01 18:53 UTC (permalink / raw)
  To: davem; +Cc: linux-bluetooth, netdev

[-- Attachment #1: Type: text/plain, Size: 3153 bytes --]

Hi Dave,

Here's (most likely) the last bluetooth-next pull request for the 4.17
kernel:

 - Remove unused btuart_cs driver (replaced by serial_cs + hci_uart)
 - New USB ID for Edimax EW-7611ULB controller
 - Cleanups & fixes to hci_bcm driver
 - Clenups to btmrvl driver

Please let me know if there are any issues pulling. Thanks.

Johan

---
The following changes since commit 06b19fe9a6df7aaa423cd8404ebe5ac9ec4b2960:

  Merge branch 'chelsio-inline-tls' (2018-03-31 23:37:33 -0400)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git for-upstream

for you to fetch changes up to 9ea471320e1302be0fac67c14a7ab7982609fea7:

  Bluetooth: Mark expected switch fall-throughs (2018-04-01 21:43:03 +0300)

----------------------------------------------------------------
Gustavo A. R. Silva (1):
      Bluetooth: Mark expected switch fall-throughs

Hans de Goede (6):
      Bluetooth: hci_bcm: Add irq_polarity module option
      Bluetooth: hci_bcm: Treat Interrupt ACPI resources as always being active-low
      Bluetooth: hci_bcm: Add 6 new ACPI HIDs
      Bluetooth: hci_bcm: Remove duplication in gpio-mappings declaration
      Bluetooth: hci_bcm: Do not tie GPIO pin order to a specific ACPI HID
      Bluetooth: hci_bcm: Add ACPI HIDs found in Windows .inf files and DSTDs

Ian W MORRISON (1):
      Bluetooth: hci_bcm: Remove DMI quirk for the MINIX Z83-4

Jaganath Kanakkassery (1):
      Bluetooth: Fix data type of appearence

Loic Poulain (1):
      Bluetooth: hci_bcm: use gpiod cansleep version

Marcel Holtmann (5):
      Bluetooth: hci_bcm: Use default baud rate if missing shutdown GPIO
      Bluetooth: hci_ll: Use skb_put_u8 instead of struct hcill_cmd
      Bluetooth: hci_ll: Convert to use h4_recv_buf helper
      Bluetooth: bpa10x: Use separate h4_recv_buf helper
      Bluetooth: Remove unused btuart_cs driver

Markus Elfring (2):
      Bluetooth: btmrvl: Delete an unnecessary variable initialisation in btmrvl_sdio_register_dev()
      Bluetooth: btmrvl: Delete an unnecessary variable initialisation in btmrvl_sdio_card_to_host()

Vic Wei (1):
      Bluetooth: Set HCI_QUIRK_SIMULTANEOUS_DISCOVERY for BTUSB_QCA_ROME

Vicente Bergas (1):
      Bluetooth: btusb: Add USB ID 7392:a611 for Edimax EW-7611ULB

Wei Yongjun (1):
      Bluetooth: btrsi: remove unused including <linux/version.h>

 drivers/bluetooth/Kconfig       |  20 +-
 drivers/bluetooth/Makefile      |   1 -
 drivers/bluetooth/bpa10x.c      |   2 +-
 drivers/bluetooth/btmrvl_sdio.c |   4 +-
 drivers/bluetooth/btrsi.c       |   1 -
 drivers/bluetooth/btuart_cs.c   | 675 ----------------------------------------
 drivers/bluetooth/btusb.c       |   4 +
 drivers/bluetooth/h4_recv.h     | 160 ++++++++++
 drivers/bluetooth/hci_bcm.c     | 305 +++++++++++++-----
 drivers/bluetooth/hci_ll.c      | 222 +++++--------
 include/net/bluetooth/mgmt.h    |   2 +-
 net/bluetooth/mgmt.c            |   1 +
 net/bluetooth/rfcomm/sock.c     |   1 +
 13 files changed, 473 insertions(+), 925 deletions(-)
 delete mode 100644 drivers/bluetooth/btuart_cs.c
 create mode 100644 drivers/bluetooth/h4_recv.h

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: [PATCH] net: improve ipv4 performances
From: Stephen Hemminger @ 2018-04-01 18:50 UTC (permalink / raw)
  To: Anton Gary Ceph; +Cc: netdev, linux-kernel
In-Reply-To: <20180401183121.13022-1-agaceph@gmail.com>

On Sun,  1 Apr 2018 20:31:21 +0200
Anton Gary Ceph <agaceph@gmail.com> wrote:

> As the Linux networking stack is growing, more and more protocols are
> added, increasing the complexity of stack itself.
> Modern processors, contrary to common belief, are very bad in branch
> prediction, so it's our task to give hints to the compiler when possible.
> 
> After a few profiling and analysis, turned out that the ethertype field
> of the packets has the following distribution:
> 
>     92.1% ETH_P_IP
>      3.2% ETH_P_ARP
>      2.7% ETH_P_8021Q
>      1.4% ETH_P_PPP_SES
>      0.6% don't know/no opinion
> 
> From a projection on statistics collected by Google about IPv6 adoption[1],
> IPv6 should peak at 25% usage at the beginning of 2030. Hence, we should
> give proper hints to the compiler about the low IPv6 usage.
> 
> Here is an iperf3 run before and after the patch:
> 
> Before:
> [ ID]  Interval           Transfer    Bandwidth       Retr
> [  4]  0.00-100.00 sec    100 GBytes  8.60 Gbits/sec  0       sender
> [  4]  0.00-100.00 sec    100 GBytes  8.60 Gbits/sec          receiver
> 
> After
> [ ID]  Interval           Transfer    Bandwidth       Retr
> [  4]  0.00-100.00 sec    109 GBytes  9.35 Gbits/sec  0       sender
> [  4]  0.00-100.00 sec    109 GBytes  9.35 Gbits/sec          receiver
> 
> [1] https://www.google.com/intl/en/ipv6/statistics.html
> 
> Signed-off-by: Anton Gary Ceph <agaceph@gmail.com>

I am surprised it makes that much of an impact.

It would be easier to manage future bisection if the big patch
was split into several pieces. Bridge,  bonding, netfilter, etc.
There doesn't appear to be any direct cross dependencies.

^ permalink raw reply

* [PATCH] net: improve ipv4 performances
From: Anton Gary Ceph @ 2018-04-01 18:31 UTC (permalink / raw)
  To: netdev, linux-kernel

As the Linux networking stack is growing, more and more protocols are
added, increasing the complexity of stack itself.
Modern processors, contrary to common belief, are very bad in branch
prediction, so it's our task to give hints to the compiler when possible.

After a few profiling and analysis, turned out that the ethertype field
of the packets has the following distribution:

    92.1% ETH_P_IP
     3.2% ETH_P_ARP
     2.7% ETH_P_8021Q
     1.4% ETH_P_PPP_SES
     0.6% don't know/no opinion

>From a projection on statistics collected by Google about IPv6 adoption[1],
IPv6 should peak at 25% usage at the beginning of 2030. Hence, we should
give proper hints to the compiler about the low IPv6 usage.

Here is an iperf3 run before and after the patch:

Before:
[ ID]  Interval           Transfer    Bandwidth       Retr
[  4]  0.00-100.00 sec    100 GBytes  8.60 Gbits/sec  0       sender
[  4]  0.00-100.00 sec    100 GBytes  8.60 Gbits/sec          receiver

After
[ ID]  Interval           Transfer    Bandwidth       Retr
[  4]  0.00-100.00 sec    109 GBytes  9.35 Gbits/sec  0       sender
[  4]  0.00-100.00 sec    109 GBytes  9.35 Gbits/sec          receiver

[1] https://www.google.com/intl/en/ipv6/statistics.html

Signed-off-by: Anton Gary Ceph <agaceph@gmail.com>
---
 drivers/net/bonding/bond_main.c    |  2 +-
 drivers/net/ipvlan/ipvlan_core.c   |  2 +-
 drivers/net/vxlan.c                |  6 +++---
 include/linux/netdevice.h          |  2 +-
 include/net/ip_tunnels.h           |  2 +-
 include/net/netfilter/nf_queue.h   |  4 ++--
 net/bridge/br_device.c             |  2 +-
 net/bridge/br_input.c              |  2 +-
 net/bridge/br_mdb.c                |  5 +++--
 net/bridge/br_multicast.c          | 18 +++++++++---------
 net/bridge/br_netfilter_hooks.c    |  9 +++++----
 net/bridge/br_private.h            |  2 +-
 net/core/dev.c                     |  2 +-
 net/core/filter.c                  |  8 ++++----
 net/core/skbuff.c                  |  2 +-
 net/core/tso.c                     |  2 +-
 net/ipv4/ip_gre.c                  |  6 +++---
 net/ipv4/ip_tunnel.c               | 12 ++++++------
 net/ipv4/ping.c                    | 10 +++++-----
 net/ipv6/datagram.c                |  6 +++---
 net/netfilter/nf_flow_table_inet.c |  2 +-
 net/netfilter/nf_tables_netdev.c   |  2 +-
 net/netfilter/nfnetlink_queue.c    |  2 +-
 net/openvswitch/actions.c          |  2 +-
 net/openvswitch/conntrack.c        | 16 ++++++++--------
 net/openvswitch/flow.c             |  4 ++--
 net/openvswitch/flow.h             |  2 +-
 net/openvswitch/flow_netlink.c     | 18 +++++++++---------
 net/xfrm/xfrm_output.c             |  2 +-
 29 files changed, 78 insertions(+), 76 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b7b113018853..b3ad2a8c1a08 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3222,7 +3222,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
 		noff += iph->ihl << 2;
 		if (!ip_is_fragment(iph))
 			proto = iph->protocol;
-	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+	} else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6))))
 			return false;
 		iph6 = ipv6_hdr(skb);
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index c1f008fe4e1d..7344e2402003 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -480,7 +480,7 @@ static int ipvlan_process_outbound(struct sk_buff *skb)
 		skb_reset_network_header(skb);
 	}
 
-	if (skb->protocol == htons(ETH_P_IPV6))
+	if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 		ret = ipvlan_process_v6_outbound(skb);
 	else if (skb->protocol == htons(ETH_P_IP))
 		ret = ipvlan_process_v4_outbound(skb);
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index fab7a4db249e..8143b99e098f 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1694,7 +1694,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 		return false;
 
 	n = NULL;
-	switch (ntohs(eth_hdr(skb)->h_proto)) {
+	switch (__builtin_expect(ntohs(eth_hdr(skb)->h_proto), ETH_P_IP)) {
 	case ETH_P_IP:
 	{
 		struct iphdr *pip;
@@ -2274,7 +2274,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 		if (ntohs(eth->h_proto) == ETH_P_ARP)
 			return arp_reduce(dev, skb, vni);
 #if IS_ENABLED(CONFIG_IPV6)
-		else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
+		else if (unlikely(ntohs(eth->h_proto) == ETH_P_IPV6) &&
 			 pskb_may_pull(skb, sizeof(struct ipv6hdr) +
 					    sizeof(struct nd_msg)) &&
 			 ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
@@ -2293,7 +2293,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	if (f && (f->flags & NTF_ROUTER) && (vxlan->cfg.flags & VXLAN_F_RSC) &&
 	    (ntohs(eth->h_proto) == ETH_P_IP ||
-	     ntohs(eth->h_proto) == ETH_P_IPV6)) {
+	     unlikely(ntohs(eth->h_proto) == ETH_P_IPV6))) {
 		did_rsc = route_shortcircuit(dev, skb);
 		if (did_rsc)
 			f = vxlan_find_mac(vxlan, eth->h_dest, vni);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5eef6c8e2741..c1a4820622f9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4031,7 +4031,7 @@ static inline bool can_checksum_protocol(netdev_features_t features,
 		return true;
 	}
 
-	switch (protocol) {
+	switch (__builtin_expect(protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return !!(features & NETIF_F_IP_CSUM);
 	case htons(ETH_P_IPV6):
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 1f16773cfd76..f837867ff3b7 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -355,7 +355,7 @@ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
 {
 	if (skb->protocol == htons(ETH_P_IP))
 		return iph->tos;
-	else if (skb->protocol == htons(ETH_P_IPV6))
+	else if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 		return ipv6_get_dsfield((const struct ipv6hdr *)iph);
 	else
 		return 0;
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index a50a69f5334c..c97b6a7719f4 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -79,7 +79,7 @@ static inline u32 hash_bridge(const struct sk_buff *skb, u32 initval)
 	struct ipv6hdr *ip6h, _ip6h;
 	struct iphdr *iph, _iph;
 
-	switch (eth_hdr(skb)->h_proto) {
+	switch (__builtin_expect(eth_hdr(skb)->h_proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		iph = skb_header_pointer(skb, skb_network_offset(skb),
 					 sizeof(*iph), &_iph);
@@ -101,7 +101,7 @@ static inline u32
 nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family,
 	     u32 initval)
 {
-	switch (family) {
+	switch (__builtin_expect(family, NFPROTO_IPV4)) {
 	case NFPROTO_IPV4:
 		queue += reciprocal_scale(hash_v4(ip_hdr(skb), initval),
 					  queues_total);
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 1285ca30ab0a..881c4bc794b9 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -70,7 +70,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 	    br->neigh_suppress_enabled) {
 		br_do_proxy_suppress_arp(skb, br, vid, NULL);
 	} else if (IS_ENABLED(CONFIG_IPV6) &&
-		   skb->protocol == htons(ETH_P_IPV6) &&
+		   unlikely(skb->protocol == htons(ETH_P_IPV6)) &&
 		   br->neigh_suppress_enabled &&
 		   pskb_may_pull(skb, sizeof(struct ipv6hdr) +
 				 sizeof(struct nd_msg)) &&
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 7f98a7d25866..6b8e4d808424 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -120,7 +120,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 	     skb->protocol == htons(ETH_P_RARP))) {
 		br_do_proxy_suppress_arp(skb, br, vid, p);
 	} else if (IS_ENABLED(CONFIG_IPV6) &&
-		   skb->protocol == htons(ETH_P_IPV6) &&
+		   unlikely(skb->protocol == htons(ETH_P_IPV6)) &&
 		   br->neigh_suppress_enabled &&
 		   pskb_may_pull(skb, sizeof(struct ipv6hdr) +
 				 sizeof(struct nd_msg)) &&
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 6d9f48bd374a..4c019c8d6e22 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -128,7 +128,8 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
 				if (p->addr.proto == htons(ETH_P_IP))
 					e.addr.u.ip4 = p->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-				if (p->addr.proto == htons(ETH_P_IPV6))
+				if (unlikely(p->addr.proto ==
+					     htons(ETH_P_IPV6)))
 					e.addr.u.ip6 = p->addr.u.ip6;
 #endif
 				e.addr.proto = p->addr.proto;
@@ -488,7 +489,7 @@ static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
 		if (ipv4_is_local_multicast(entry->addr.u.ip4))
 			return false;
 #if IS_ENABLED(CONFIG_IPV6)
-	} else if (entry->addr.proto == htons(ETH_P_IPV6)) {
+	} else if (unlikely(entry->addr.proto == htons(ETH_P_IPV6))) {
 		if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6))
 			return false;
 #endif
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index cb4729539b82..1c978838b81a 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -62,7 +62,7 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
 		return 0;
 	if (a->vid != b->vid)
 		return 0;
-	switch (a->proto) {
+	switch (__builtin_expect(a->proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return a->u.ip4 == b->u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -92,7 +92,7 @@ static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
 static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
 			     struct br_ip *ip)
 {
-	switch (ip->proto) {
+	switch (__builtin_expect(ip->proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return __br_ip4_hash(mdb, ip->u.ip4, ip->vid);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -167,7 +167,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
 	ip.proto = skb->protocol;
 	ip.vid = vid;
 
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		ip.u.ip4 = ip_hdr(skb)->daddr;
 		break;
@@ -577,7 +577,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
 						struct br_ip *addr,
 						u8 *igmp_type)
 {
-	switch (addr->proto) {
+	switch (__builtin_expect(addr->proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return br_ip4_multicast_alloc_query(br, addr->u.ip4, igmp_type);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1321,7 +1321,7 @@ static bool br_multicast_select_querier(struct net_bridge *br,
 					struct net_bridge_port *port,
 					struct br_ip *saddr)
 {
-	switch (saddr->proto) {
+	switch (__builtin_expect(saddr->proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return br_ip4_multicast_select_querier(br, port, saddr->u.ip4);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1761,7 +1761,7 @@ static void br_multicast_err_count(const struct net_bridge *br,
 	pstats = this_cpu_ptr(stats);
 
 	u64_stats_update_begin(&pstats->syncp);
-	switch (proto) {
+	switch (__builtin_expect(proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		pstats->mstats.igmp_parse_errors++;
 		break;
@@ -1909,7 +1909,7 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
 	if (br->multicast_disabled)
 		return 0;
 
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		ret = br_multicast_ipv4_rcv(br, port, skb, vid);
 		break;
@@ -2461,7 +2461,7 @@ bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto)
 
 	br = port->br;
 
-	switch (proto) {
+	switch (__builtin_expect(proto, ETH_P_IP)) {
 	case ETH_P_IP:
 		if (!timer_pending(&br->ip4_other_query.timer) ||
 		    rcu_dereference(br->ip4_querier.port) == port)
@@ -2493,7 +2493,7 @@ static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
 	unsigned int t_len;
 
 	u64_stats_update_begin(&pstats->syncp);
-	switch (proto) {
+	switch (__builtin_expect(proto, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		t_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
 		switch (type) {
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 9b16eaf33819..c622781eaa47 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -73,7 +73,8 @@ static int brnf_pass_vlan_indev __read_mostly;
 	(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
 
 #define IS_IPV6(skb) \
-	(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IPV6))
+	(!skb_vlan_tag_present(skb) && \
+	 unlikely(skb->protocol == htons(ETH_P_IPV6)))
 
 #define IS_ARP(skb) \
 	(!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_ARP))
@@ -93,7 +94,7 @@ static inline __be16 vlan_proto(const struct sk_buff *skb)
 	 brnf_filter_vlan_tagged)
 
 #define IS_VLAN_IPV6(skb) \
-	(vlan_proto(skb) == htons(ETH_P_IPV6) && \
+	 unlikely(vlan_proto(skb) == htons(ETH_P_IPV6) && \
 	 brnf_filter_vlan_tagged)
 
 #define IS_VLAN_ARP(skb) \
@@ -534,7 +535,7 @@ static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff
 		if (skb->protocol == htons(ETH_P_IP))
 			nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
 
-		if (skb->protocol == htons(ETH_P_IPV6))
+		if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 			nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
 
 		in = nf_bridge->physindev;
@@ -749,7 +750,7 @@ static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff
 		return br_nf_ip_fragment(net, sk, skb, br_nf_push_frag_xmit);
 	}
 	if (IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) &&
-	    skb->protocol == htons(ETH_P_IPV6)) {
+	    unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
 		struct brnf_frag_data *data;
 
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 8e13a64d8c99..a208cc627662 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -686,7 +686,7 @@ __br_multicast_querier_exists(struct net_bridge *br,
 static inline bool br_multicast_querier_exists(struct net_bridge *br,
 					       struct ethhdr *eth)
 {
-	switch (eth->h_proto) {
+	switch (__builtin_expect(eth->h_proto, ETH_P_IP)) {
 	case (htons(ETH_P_IP)):
 		return __br_multicast_querier_exists(br,
 			&br->ip4_other_query, false);
diff --git a/net/core/dev.c b/net/core/dev.c
index ef0cc6ea5f8d..f829f0a68a94 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4395,7 +4395,7 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
  */
 static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
 {
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_ARP):
 	case htons(ETH_P_IP):
 	case htons(ETH_P_IPV6):
diff --git a/net/core/filter.c b/net/core/filter.c
index 48aa7c7320db..6b7ab16505aa 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2170,11 +2170,11 @@ static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto)
 	__be16 from_proto = skb->protocol;
 
 	if (from_proto == htons(ETH_P_IP) &&
-	      to_proto == htons(ETH_P_IPV6))
+	      unlikely(to_proto == htons(ETH_P_IPV6)))
 		return bpf_skb_proto_4_to_6(skb);
 
-	if (from_proto == htons(ETH_P_IPV6) &&
-	      to_proto == htons(ETH_P_IP))
+	if (unlikely(from_proto == htons(ETH_P_IPV6)) &&
+	    to_proto == htons(ETH_P_IP))
 		return bpf_skb_proto_6_to_4(skb);
 
 	return -ENOTSUPP;
@@ -2240,7 +2240,7 @@ static const struct bpf_func_proto bpf_skb_change_type_proto = {
 
 static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
 {
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return sizeof(struct iphdr);
 	case htons(ETH_P_IPV6):
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 857e4e6f751a..6236c7c18740 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4642,7 +4642,7 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate)
 {
 	int err;
 
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		err = skb_checksum_setup_ipv4(skb, recalculate);
 		break;
diff --git a/net/core/tso.c b/net/core/tso.c
index 43f4eba61933..85da3c3b498b 100644
--- a/net/core/tso.c
+++ b/net/core/tso.c
@@ -21,7 +21,7 @@ void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
 	int mac_hdr_len = skb_network_offset(skb);
 
 	memcpy(hdr, skb->data, hdr_len);
-	if (!tso->ipv6) {
+	if (likely(!tso->ipv6)) {
 		struct iphdr *iph = (void *)(hdr + mac_hdr_len);
 
 		iph->id = htons(tso->ip_id);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 0901de42ed85..6cf3e3e4cca3 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -189,9 +189,9 @@ static void ipgre_err(struct sk_buff *skb, u32 info,
 		return;
 
 #if IS_ENABLED(CONFIG_IPV6)
-       if (tpi->proto == htons(ETH_P_IPV6) &&
-           !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
-				       type, data_len))
+	if (unlikely(tpi->proto == htons(ETH_P_IPV6)) &&
+	    !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len,
+					type, data_len))
                return;
 #endif
 
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index a7fd1c5a2a14..74ac2caff5a5 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -541,7 +541,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
 		}
 	}
 #if IS_ENABLED(CONFIG_IPV6)
-	else if (skb->protocol == htons(ETH_P_IPV6)) {
+	else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
 
 		if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
@@ -587,7 +587,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
 	if (tos == 1) {
 		if (skb->protocol == htons(ETH_P_IP))
 			tos = inner_iph->tos;
-		else if (skb->protocol == htons(ETH_P_IPV6))
+		else if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
 	}
 	init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0,
@@ -609,7 +609,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
 	if (ttl == 0) {
 		if (skb->protocol == htons(ETH_P_IP))
 			ttl = inner_iph->ttl;
-		else if (skb->protocol == htons(ETH_P_IPV6))
+		else if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 			ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
 		else
 			ttl = ip4_dst_hoplimit(&rt->dst);
@@ -671,7 +671,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 			dst = rt_nexthop(rt, inner_iph->daddr);
 		}
 #if IS_ENABLED(CONFIG_IPV6)
-		else if (skb->protocol == htons(ETH_P_IPV6)) {
+		else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 			const struct in6_addr *addr6;
 			struct neighbour *neigh;
 			bool do_tx_error_icmp;
@@ -713,7 +713,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 		if (skb->protocol == htons(ETH_P_IP)) {
 			tos = inner_iph->tos;
 			connected = false;
-		} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		} else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 			tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
 			connected = false;
 		}
@@ -768,7 +768,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 		if (skb->protocol == htons(ETH_P_IP))
 			ttl = inner_iph->ttl;
 #if IS_ENABLED(CONFIG_IPV6)
-		else if (skb->protocol == htons(ETH_P_IPV6))
+		else if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 			ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
 #endif
 		else
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index b8f0db54b197..64b3eaa84974 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -183,7 +183,7 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 		pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
 			 (int)ident, &ip_hdr(skb)->daddr, dif);
 #if IS_ENABLED(CONFIG_IPV6)
-	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+	} else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
 			 (int)ident, &ipv6_hdr(skb)->daddr, dif);
 #endif
@@ -208,7 +208,7 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 			    isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
 				continue;
 #if IS_ENABLED(CONFIG_IPV6)
-		} else if (skb->protocol == htons(ETH_P_IPV6) &&
+		} else if (unlikely(skb->protocol == htons(ETH_P_IPV6)) &&
 			   sk->sk_family == AF_INET6) {
 
 			pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
@@ -497,7 +497,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
 		type = icmp_hdr(skb)->type;
 		code = icmp_hdr(skb)->code;
 		icmph = (struct icmphdr *)(skb->data + offset);
-	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+	} else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		family = AF_INET6;
 		type = icmp6_hdr(skb)->icmp6_type;
 		code = icmp6_hdr(skb)->icmp6_code;
@@ -565,7 +565,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
 			break;
 		}
 #if IS_ENABLED(CONFIG_IPV6)
-	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+	} else if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 		harderr = pingv6_ops.icmpv6_err_convert(type, code, &err);
 #endif
 	}
@@ -929,7 +929,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
 
 		if (inet6_sk(sk)->rxopt.all)
 			pingv6_ops.ip6_datagram_recv_common_ctl(sk, msg, skb);
-		if (skb->protocol == htons(ETH_P_IPV6) &&
+		if (unlikely(skb->protocol == htons(ETH_P_IPV6)) &&
 		    inet6_sk(sk)->rxopt.all)
 			pingv6_ops.ip6_datagram_recv_specific_ctl(sk, msg, skb);
 		else if (skb->protocol == htons(ETH_P_IP) && isk->cmsg_flags)
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index a9f7eca0b6a3..230249917ffc 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -474,7 +474,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 		sin->sin6_family = AF_INET6;
 		sin->sin6_flowinfo = 0;
 		sin->sin6_port = serr->port;
-		if (skb->protocol == htons(ETH_P_IPV6)) {
+		if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 			const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
 								  struct ipv6hdr, daddr);
 			sin->sin6_addr = ip6h->daddr;
@@ -499,7 +499,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 		sin->sin6_family = AF_INET6;
 		if (np->rxopt.all)
 			ip6_datagram_recv_common_ctl(sk, msg, skb);
-		if (skb->protocol == htons(ETH_P_IPV6)) {
+		if (unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 			sin->sin6_addr = ipv6_hdr(skb)->saddr;
 			if (np->rxopt.all)
 				ip6_datagram_recv_specific_ctl(sk, msg, skb);
@@ -587,7 +587,7 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
 	if (np->rxopt.bits.rxinfo) {
 		struct in6_pktinfo src_info;
 
-		if (is_ipv6) {
+		if (unlikely(is_ipv6)) {
 			src_info.ipi6_ifindex = IP6CB(skb)->iif;
 			src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
 		} else {
diff --git a/net/netfilter/nf_flow_table_inet.c b/net/netfilter/nf_flow_table_inet.c
index 375a1881d93d..17c89edcde70 100644
--- a/net/netfilter/nf_flow_table_inet.c
+++ b/net/netfilter/nf_flow_table_inet.c
@@ -10,7 +10,7 @@ static unsigned int
 nf_flow_offload_inet_hook(void *priv, struct sk_buff *skb,
 			  const struct nf_hook_state *state)
 {
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		return nf_flow_offload_ip_hook(priv, skb, state);
 	case htons(ETH_P_IPV6):
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
index 4041fafca934..0fc5cc45d238 100644
--- a/net/netfilter/nf_tables_netdev.c
+++ b/net/netfilter/nf_tables_netdev.c
@@ -23,7 +23,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
 
 	nft_set_pktinfo(&pkt, skb, state);
 
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		nft_set_pktinfo_ipv4_validate(&pkt, skb);
 		break;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 8bba23160a68..9db1303a3c9f 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -774,7 +774,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
 
 	skb = entry->skb;
 
-	switch (entry->state.pf) {
+	switch (__builtin_expect(entry->state.pf, NFPROTO_IPV4)) {
 	case NFPROTO_IPV4:
 		skb->protocol = htons(ETH_P_IP);
 		break;
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 30a5df27116e..ae7ddba3232b 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -909,7 +909,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
 
 		ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
 		refdst_drop(orig_dst);
-	} else if (key->eth.type == htons(ETH_P_IPV6)) {
+	} else if (unlikely(key->eth.type == htons(ETH_P_IPV6))) {
 		const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
 		unsigned long orig_dst;
 		struct rt6_info ovs_rt;
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index c5904f629091..aeebcb46af8e 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -82,7 +82,7 @@ static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info);
 
 static u16 key_to_nfproto(const struct sw_flow_key *key)
 {
-	switch (ntohs(key->eth.type)) {
+	switch (__builtin_expect(ntohs(key->eth.type), ETH_P_IP)) {
 	case ETH_P_IP:
 		return NFPROTO_IPV4;
 	case ETH_P_IPV6:
@@ -188,7 +188,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
 			key->ipv4.ct_orig.dst = orig->dst.u3.ip;
 			__ovs_ct_update_key_orig_tp(key, orig, IPPROTO_ICMP);
 			return;
-		} else if (key->eth.type == htons(ETH_P_IPV6) &&
+		} else if (unlikely(key->eth.type == htons(ETH_P_IPV6)) &&
 			   !sw_flow_key_is_nd(key) &&
 			   nf_ct_l3num(ct) == NFPROTO_IPV6) {
 			key->ipv6.ct_orig.src = orig->src.u3.in6;
@@ -289,7 +289,7 @@ int ovs_ct_put_key(const struct sw_flow_key *swkey,
 			if (nla_put(skb, OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4,
 				    sizeof(orig), &orig))
 				return -EMSGSIZE;
-		} else if (swkey->eth.type == htons(ETH_P_IPV6)) {
+		} else if (unlikely(swkey->eth.type == htons(ETH_P_IPV6))) {
 			struct ovs_key_ct_tuple_ipv6 orig = {
 				IN6_ADDR_INITIALIZER(output->ipv6.ct_orig.src),
 				IN6_ADDR_INITIALIZER(output->ipv6.ct_orig.dst),
@@ -484,7 +484,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key,
 
 		ovs_cb.mru = IPCB(skb)->frag_max_size;
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
-	} else if (key->eth.type == htons(ETH_P_IPV6)) {
+	} else if (unlikely(key->eth.type == htons(ETH_P_IPV6))) {
 		enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
 
 		memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
@@ -735,7 +735,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
 				err = NF_DROP;
 			goto push;
 		} else if (IS_ENABLED(CONFIG_NF_NAT_IPV6) &&
-			   skb->protocol == htons(ETH_P_IPV6)) {
+			   unlikely(skb->protocol == htons(ETH_P_IPV6))) {
 			__be16 frag_off;
 			u8 nexthdr = ipv6_hdr(skb)->nexthdr;
 			int hdrlen = ipv6_skip_exthdr(skb,
@@ -797,7 +797,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key,
 		key->ct_state |= OVS_CS_F_SRC_NAT;
 		if (key->eth.type == htons(ETH_P_IP))
 			key->ipv4.addr.src = ip_hdr(skb)->saddr;
-		else if (key->eth.type == htons(ETH_P_IPV6))
+		else if (unlikely(key->eth.type == htons(ETH_P_IPV6)))
 			memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr,
 			       sizeof(key->ipv6.addr.src));
 		else
@@ -819,7 +819,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key,
 		key->ct_state |= OVS_CS_F_DST_NAT;
 		if (key->eth.type == htons(ETH_P_IP))
 			key->ipv4.addr.dst = ip_hdr(skb)->daddr;
-		else if (key->eth.type == htons(ETH_P_IPV6))
+		else if (unlikely(key->eth.type == htons(ETH_P_IPV6)))
 			memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr,
 			       sizeof(key->ipv6.addr.dst));
 		else
@@ -1109,7 +1109,7 @@ static int ovs_skb_network_trim(struct sk_buff *skb)
 	unsigned int len;
 	int err;
 
-	switch (skb->protocol) {
+	switch (__builtin_expect(skb->protocol, ETH_P_IP)) {
 	case htons(ETH_P_IP):
 		len = ntohs(ip_hdr(skb)->tot_len);
 		break;
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 56b8e7167790..f959364c29e8 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -735,7 +735,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 
 			stack_len += MPLS_HLEN;
 		}
-	} else if (key->eth.type == htons(ETH_P_IPV6)) {
+	} else if (unlikely(key->eth.type == htons(ETH_P_IPV6))) {
 		int nh_len;             /* IPv6 Header + Extensions */
 
 		nh_len = parse_ipv6hdr(skb, key);
@@ -910,7 +910,7 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
 	    key->eth.type != htons(ETH_P_IP))
 		return -EINVAL;
 	if (attrs & (1 << OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6) &&
-	    (key->eth.type != htons(ETH_P_IPV6) ||
+	    (likely(key->eth.type != htons(ETH_P_IPV6)) ||
 	     sw_flow_key_is_nd(key)))
 		return -EINVAL;
 
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index c670dd24b8b7..63d280c42f10 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -165,7 +165,7 @@ struct sw_flow_key {
 
 static inline bool sw_flow_key_is_nd(const struct sw_flow_key *key)
 {
-	return key->eth.type == htons(ETH_P_IPV6) &&
+	return unlikely(key->eth.type == htons(ETH_P_IPV6)) &&
 		key->ip.proto == NEXTHDR_ICMP &&
 		key->tp.dst == 0 &&
 		(key->tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) ||
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 7322aa1e382e..33ba451efbf6 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -238,7 +238,7 @@ static bool match_validate(const struct sw_flow_match *match,
 		}
 	}
 
-	if (match->key->eth.type == htons(ETH_P_IPV6)) {
+	if (unlikely(match->key->eth.type == htons(ETH_P_IPV6))) {
 		key_expected |= 1 << OVS_KEY_ATTR_IPV6;
 		if (match->mask && match->mask->key.eth.type == htons(0xffff)) {
 			mask_allowed |= 1 << OVS_KEY_ATTR_IPV6;
@@ -2070,7 +2070,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
 		ipv4_key->ipv4_tos = output->ip.tos;
 		ipv4_key->ipv4_ttl = output->ip.ttl;
 		ipv4_key->ipv4_frag = output->ip.frag;
-	} else if (swkey->eth.type == htons(ETH_P_IPV6)) {
+	} else if (unlikely(swkey->eth.type == htons(ETH_P_IPV6))) {
 		struct ovs_key_ipv6 *ipv6_key;
 
 		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV6, sizeof(*ipv6_key));
@@ -2114,7 +2114,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
 	}
 
 	if ((swkey->eth.type == htons(ETH_P_IP) ||
-	     swkey->eth.type == htons(ETH_P_IPV6)) &&
+	     unlikely(swkey->eth.type == htons(ETH_P_IPV6))) &&
 	     swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
 
 		if (swkey->ip.proto == IPPROTO_TCP) {
@@ -2157,7 +2157,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
 			icmp_key = nla_data(nla);
 			icmp_key->icmp_type = ntohs(output->tp.src);
 			icmp_key->icmp_code = ntohs(output->tp.dst);
-		} else if (swkey->eth.type == htons(ETH_P_IPV6) &&
+		} else if (unlikely(swkey->eth.type == htons(ETH_P_IPV6)) &&
 			   swkey->ip.proto == IPPROTO_ICMPV6) {
 			struct ovs_key_icmpv6 *icmpv6_key;
 
@@ -2682,7 +2682,7 @@ static int validate_set(const struct nlattr *a,
 		break;
 
 	case OVS_KEY_ATTR_IPV6:
-		if (eth_type != htons(ETH_P_IPV6))
+		if (likely(eth_type != htons(ETH_P_IPV6)))
 			return -EINVAL;
 
 		ipv6_key = nla_data(ovs_key);
@@ -2711,7 +2711,7 @@ static int validate_set(const struct nlattr *a,
 
 	case OVS_KEY_ATTR_TCP:
 		if ((eth_type != htons(ETH_P_IP) &&
-		     eth_type != htons(ETH_P_IPV6)) ||
+		     likely(eth_type != htons(ETH_P_IPV6))) ||
 		    flow_key->ip.proto != IPPROTO_TCP)
 			return -EINVAL;
 
@@ -2719,7 +2719,7 @@ static int validate_set(const struct nlattr *a,
 
 	case OVS_KEY_ATTR_UDP:
 		if ((eth_type != htons(ETH_P_IP) &&
-		     eth_type != htons(ETH_P_IPV6)) ||
+		     likely(eth_type != htons(ETH_P_IPV6))) ||
 		    flow_key->ip.proto != IPPROTO_UDP)
 			return -EINVAL;
 
@@ -2732,7 +2732,7 @@ static int validate_set(const struct nlattr *a,
 
 	case OVS_KEY_ATTR_SCTP:
 		if ((eth_type != htons(ETH_P_IP) &&
-		     eth_type != htons(ETH_P_IPV6)) ||
+		     likely(eth_type != htons(ETH_P_IPV6))) ||
 		    flow_key->ip.proto != IPPROTO_SCTP)
 			return -EINVAL;
 
@@ -2924,7 +2924,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 			 */
 			if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
 			    (eth_type != htons(ETH_P_IP) &&
-			     eth_type != htons(ETH_P_IPV6) &&
+			     likely(eth_type != htons(ETH_P_IPV6)) &&
 			     eth_type != htons(ETH_P_ARP) &&
 			     eth_type != htons(ETH_P_RARP) &&
 			     !eth_p_mpls(eth_type)))
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 89b178a78dc7..870cd06adbef 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -279,7 +279,7 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)
 
 	if (skb->protocol == htons(ETH_P_IP))
 		proto = AF_INET;
-	else if (skb->protocol == htons(ETH_P_IPV6))
+	else if (unlikely(skb->protocol == htons(ETH_P_IPV6)))
 		proto = AF_INET6;
 	else
 		return;
-- 
2.14.3

^ permalink raw reply related

* Re: [PATCH v4 iproute2-next 0/7] cm_id, cq, mr, and pd resource tracking
From: Leon Romanovsky @ 2018-04-01 18:29 UTC (permalink / raw)
  To: David Ahern; +Cc: Steve Wise, stephen, netdev, linux-rdma
In-Reply-To: <8cdcb764-da42-e540-90e6-309eda0eb599@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1744 bytes --]

On Sun, Apr 01, 2018 at 09:22:14AM -0600, David Ahern wrote:
> On 3/29/18 3:38 PM, Steve Wise wrote:
> > This series enhances the iproute2 rdma tool to include dumping of
> > connection manager id (cm_id), completion queue (cq), memory region (mr),
> > and protection domain (pd) rdma resources.  It is the user-space part of
> > the kernel resource tracking series merged into rdma-next for 4.17 [1]
> > and [2].
> >
> > Changes since v3:
> > - replaced rdma_cma.h inclusion with UAPI rdma_user_cm.h
> > - display only device names instead of device/port for cq, mr, and pd
> > since they are not associated with a specific port.
> >
> > Changes since v2:
> > - pull in rdma-core:include/rdma/rdma_cma.h
> > - 80 column reformat
> > - add reviewed-by tags
> >
> > Changes since v1/RFC:
> > - removed RFC tag
> > - initialize rd properly to avoid passing a garbage port number
> > - revert accidental change to qp_valid_filters
> > - removed cm_id dev/network/transport types
> > - cm_id ip addrs now passed up as __kernel_sockaddr_storage
> > - cm_id ip address ports printed as "address:port" strings
> > - only parse/display memory keys and iova if available
> > - filter on "users" for cqs and pds
> > - fixed memory leaks
> > - removed PD_FLAGS attribute
> > - filter on "mrlen" for mrs
> > - filter on "poll-ctx" for cqs
> > - don't require addrs or qp_type for parsing cm_ids
> > - only filter optional attrs if they are present
> > - remove PGSIZE MR attr to match kernel
> >
> > [1] https://www.spinics.net/lists/linux-rdma/msg61720.html
> > [2] https://www.spinics.net/lists/linux-rdma/msg62979.html
> >     https://www.spinics.net/lists/linux-rdma/msg62980.html
> >
> > ---
> >
>
> applied to iproute2-next. Thanks,

Thanks David

>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox