* Re: [PATCH net-next repost] openvswitch: allow output of MPLS packets on tunnel vports
From: David Miller @ 2016-03-18 22:27 UTC (permalink / raw)
To: simon.horman; +Cc: pshelar, jesse, netdev, dev
In-Reply-To: <1458010835-18555-1-git-send-email-simon.horman@netronome.com>
From: Simon Horman <simon.horman@netronome.com>
Date: Tue, 15 Mar 2016 12:00:35 +0900
> Currently output of MPLS packets on tunnel vports is not allowed by Open
> vSwitch. This is because historically encapsulation was done in such a way
> that the inner_protocol field of the skb needed to hold the inner protocol
> for both MPLS and tunnel encapsulation in order for GSO segmentation to be
> performed correctly.
>
> Since b2acd1dc3949 ("openvswitch: Use regular GRE net_device instead of
> vport") Open vSwitch makes use of lwt to output to tunnel netdevs which
> perform encapsulation. As no drivers expose support for MPLS offloads this
> means that GSO packets are segmented in software by validate_xmit_skb(),
> which is called from __dev_queue_xmit(), before tunnel encapsulation occurs.
> This means that the inner protocol of MPLS is no longer needed by the time
> encapsulation occurs and the contention on the inner_protocol field of the
> skb no longer occurs.
>
> Thus it is now safe to output MPLS to tunnel vports.
>
> Signed-off-by: Simon Horman <simon.horman@netronome.com>
Applied, thanks.
^ permalink raw reply
* Re: [patch 1/2 net-next] mediatek: checking for IS_ERR() instead of NULL
From: David Miller @ 2016-03-18 22:31 UTC (permalink / raw)
To: dan.carpenter
Cc: nbd, blogic, matthias.bgg, netdev, linux-mediatek,
kernel-janitors
In-Reply-To: <20160315071849.GH13560@mwanda>
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Tue, 15 Mar 2016 10:18:49 +0300
> of_phy_connect() returns NULL on error, it never returns error pointers.
>
> Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Applied.
^ permalink raw reply
* Re: [patch 2/2 net-next] mediatek: unlock on error in mtk_tx_map()
From: David Miller @ 2016-03-18 22:31 UTC (permalink / raw)
To: dan.carpenter
Cc: nbd, blogic, matthias.bgg, netdev, linux-mediatek,
kernel-janitors
In-Reply-To: <20160315071904.GI13560@mwanda>
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Tue, 15 Mar 2016 10:19:04 +0300
> There was a missing unlock on the error path.
>
> Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet')
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Applied.
^ permalink raw reply
* Re: [PATCH 1/1] net: stmmac: Don't search for phys if mdio node is defined.
From: David Miller @ 2016-03-18 22:31 UTC (permalink / raw)
To: preid; +Cc: peppe.cavallaro, netdev
In-Reply-To: <1458027273-127737-2-git-send-email-preid@electromag.com.au>
From: Phil Reid <preid@electromag.com.au>
Date: Tue, 15 Mar 2016 15:34:33 +0800
> If a dt mdio entry has been added least assume that we wont
> search for phys attached. The DT and of_mdiobus_register already do
> this. This stops DSA phys being found and phys created for them, as
> this is handled by the DSA driver.
>
> Signed-off-by: Phil Reid <preid@electromag.com.au>
Applied.
^ permalink raw reply
* Re: [PATCH] af_unix: closed SOCK_SEQPACKET socketpair must get SIGPIPE
From: David Miller @ 2016-03-18 22:32 UTC (permalink / raw)
To: glider; +Cc: edumazet, rweikusat, linux-kernel, netdev
In-Reply-To: <1458032624-139688-1-git-send-email-glider@google.com>
From: Alexander Potapenko <glider@google.com>
Date: Tue, 15 Mar 2016 10:03:44 +0100
> According to IEEE Std 1003.1, 2013, sending data to a SOCK_SEQPACKET
> socketpair with MSG_NOSIGNAL flag set must result in a SIGPIPE if the
> socket is no longer connected.
>
> I used the following program to check the kernel behavior:
...
> Signed-off-by: Alexander Potapenko <glider@google.com>
In the final analysis I don't think we can do this.
Properly working programs will start to mysteriously receive
signals in this situation and fail.
I'm sorry but I think we're stuck with this behavior.
^ permalink raw reply
* Re: [PATCH] sctp: align MTU to a word
From: Marcelo Ricardo Leitner @ 2016-03-18 22:33 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, Neil Horman, Vlad Yasevich, linux-sctp
In-Reply-To: <1458338974.31963.15.camel@edumazet-glaptop3.roam.corp.google.com>
On Fri, Mar 18, 2016 at 03:09:34PM -0700, Eric Dumazet wrote:
> On Fri, 2016-03-18 at 18:39 -0300, Marcelo Ricardo Leitner wrote:
>
> > - transport->pathmtu = dst_mtu(transport->dst);
> > + transport->pathmtu = dst_mtu(transport->dst) & ~3;
>
>
> Well, surely a helper doing this would be better than spreading & ~3 all
> over the places ;)
Heh.. agreed
for this and the other patch too, will post a v2
Thanks
^ permalink raw reply
* Re: [PATCH] net: consolidate lock/unlock into unlock_wait
From: Joe Perches @ 2016-03-18 22:35 UTC (permalink / raw)
To: David Miller, hofrat; +Cc: netdev, linux-kernel
In-Reply-To: <20160318.173702.788700055531273267.davem@davemloft.net>
On Fri, 2016-03-18 at 17:37 -0400, David Miller wrote:
> From: Nicholas Mc Guire <hofrat@osadl.org>
> > The spin_lock()/spin_unlock() is synchronizing on the adapter->work_lock
> > as the comment also suggests, which is equivalent to spin_unlock_wait()
> > but the later should be more efficient.
[]
> There really is no justification for this change.
> This is an optimization in a slow-path of the driver.
> The device is a rarely used older piece of hardware.
It really might be nice to take some of the ancient
hardware drivers in drivers/net and move them into
some separate subdirectory like:
drivers/net/ancient
or
drivers/net/antiques
or
drivers/net/archaic
etc...
so there's some clear designation that these crufty
old drivers don't need to be touched anymore except
for maybe when kernel wide changes occur.
^ permalink raw reply
* Re: [v6, 2/5] soc: fsl: add GUTS driver for QorIQ platforms
From: Scott Wood @ 2016-03-18 22:54 UTC (permalink / raw)
To: Yangbo Lu, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
linux-clk@vger.kernel.org, linux-i2c@vger.kernel.org,
iommu@lists.linux-foundation.org, netdev@vger.kernel.org,
linux-mmc@vger.kernel.org
Cc: Rob Herring, Russell King, Jochen Friedrich, Joerg Roedel,
Claudiu Manoil, ulf.hansson@linaro.org, Bhupesh Sharma,
Zhao Qiang, Kumar Gala, Santosh Shilimkar, Yang-Leo Li,
Xiaobo Xie
In-Reply-To: <1457518131-11339-3-git-send-email-yangbo.lu@nxp.com>
On 03/09/2016 04:18 AM, Yangbo Lu wrote:
> +#ifdef CONFIG_FSL_GUTS
> +u32 fsl_guts_get_svr(void);
> +int fsl_guts_init(void);
> +#endif
Don't ifdef prototypes (when not providing a stub alternative).
-Scott
^ permalink raw reply
* Re: [PATCH] sctp: keep fragmentation point aligned to word size
From: Marcelo Ricardo Leitner @ 2016-03-18 23:11 UTC (permalink / raw)
To: netdev; +Cc: Neil Horman, Vlad Yasevich, linux-sctp
In-Reply-To: <1458337159-22792-2-git-send-email-marcelo.leitner@gmail.com>
On Fri, Mar 18, 2016 at 06:39:17PM -0300, Marcelo Ricardo Leitner wrote:
> If the user supply a different fragmentation point or if there is a
> network header that cause it to not be aligned, force it to be aligned.
>
> Fragmentation point at a value that is not aligned is not optimal. It
> causes extra padding to be used and has just no pros.
>
> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> ---
> include/net/sctp/sctp.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
> index 835aa2ed987092634a4242314e9eabb51d1e4e35..f27d38113c7926783a9bf2863e14e963ed0ad5d6 100644
> --- a/include/net/sctp/sctp.h
> +++ b/include/net/sctp/sctp.h
> @@ -426,7 +426,7 @@ static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
> if (asoc->user_frag)
> frag = min_t(int, frag, asoc->user_frag);
>
> - frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN);
> + frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN) & ~3;
Will submit a v2 with a helper for this & ~3 thing
^ permalink raw reply
* Re: [PATCH net 1/1] qlge: Fix receive packets drop.
From: David Miller @ 2016-03-18 23:22 UTC (permalink / raw)
To: manish.chopra; +Cc: netdev, Dept-GELinuxNICDev, harish.patil
In-Reply-To: <1458040425-12937-1-git-send-email-manish.chopra@qlogic.com>
From: Manish Chopra <manish.chopra@qlogic.com>
Date: Tue, 15 Mar 2016 07:13:45 -0400
> When running small packets [length < 256 bytes] traffic, packets were
> being dropped due to invalid data in those packets which were
> delivered by the driver upto the stack. Using pci_dma_sync_single_for_cpu
> ensures copying latest and updated data into skb from the receive buffer.
>
> Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
> Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Applied and queued up for -stable.
^ permalink raw reply
* Re: [PATCH net] ravb: fix result value overwrite
From: David Miller @ 2016-03-18 23:22 UTC (permalink / raw)
To: ykaneko0929
Cc: netdev, sergei.shtylyov, horms, magnus.damm, linux-renesas-soc
In-Reply-To: <1458057136-23253-1-git-send-email-ykaneko0929@gmail.com>
From: Yoshihiro Kaneko <ykaneko0929@gmail.com>
Date: Wed, 16 Mar 2016 00:52:16 +0900
> The result value is overwritten by a return value of
> ravb_ptp_interrupt().
>
> Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH net] bnx2x: Prevent false warning for lack of FC NPIV
From: David Miller @ 2016-03-18 23:23 UTC (permalink / raw)
To: Yuval.Mintz; +Cc: netdev, Ariel.Elior, linux-scsi, andrew.patterson
In-Reply-To: <1458064324-16487-1-git-send-email-Yuval.Mintz@qlogic.com>
From: Yuval Mintz <Yuval.Mintz@qlogic.com>
Date: Tue, 15 Mar 2016 19:52:04 +0200
> Not all adapters have FC-NPIV configured. If bnx2fc is used with such an
> adapter, driver would read irrelevant data from the the nvram and log
> "FC-NPIV table with bad length..." In system logs.
>
> Simply accept that reading '0' as the feature offset in nvram indicates
> the feature isn't there and return.
>
> Reported-by: Andrew Patterson <andrew.patterson@hpe.com>
> Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Applied.
^ permalink raw reply
* [RFC PATCH 0/9] RFC6864 compliant GRO and GSO partial offload
From: Alexander Duyck @ 2016-03-18 23:24 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
This patch series addresses two things.
First it enables what I am calling RFC6864 compliant GRO. Basically what
I am doing is allowing one of two patterns for incoming frames. Either the
IP ID will increment, or if the DF bit is set it can either increment or
stay the same value. This allows us to perform GRO if the IP ID is forced
to stay at a static value as may occur if we are replicating an IP header
instead of actually having it offloaded.
The last 3 patches introduce what I am calling GSO partial. The best way
to describe it is that it is a GSO offload in which the portion pointed to
by csum_start must be handled by the hardware, and the region before that
can be optionally handled. So for example with i40e the only pieces it was
missing from the full offload was the checksum so this is computed in
software and the hardware will update inner and outer IP headers. In the
example for ixgbe the hardware will only update the outer IP header. The
outer UDP or GRE header and inner IP header are unmodified.
The bits remaining to be worked out are what to do about drivers that
wouldn't be able to handle updating the outer IP header. So for example
should I require the driver to have to update the outer IP header or handle
it in software. The one concern here is that if the outer IP header does
not have the DF bit set and does not update the IP ID field we run the risk
of causing all sorts of problems if the packet is fragmented in flight.
---
Alexander Duyck (9):
ipv4/GRO: Allow multiple frames to use the same IP ID
gre: Enforce IP ID verification on outer headers
geneve: Enforce IP ID verification on outer headers
vxlan: Enforce IP ID verification on outer headers
gue: Enforce IP ID verification on outer headers
ethtool: Add support for toggling any of the GSO offloads
GSO: Support partial segmentation offload
i40e/i40evf: Add support for GSO partial with UDP_TUNNEL_CSUM and GRE_CSUM
ixgbe/ixgbevf: Add support for GSO partial
drivers/net/ethernet/intel/i40e/i40e_main.c | 8 ++
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 14 +++-
drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 14 +++-
drivers/net/ethernet/intel/i40evf/i40evf_main.c | 8 ++
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 72 +++++++++++++-------
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 77 ++++++++++++++-------
drivers/net/geneve.c | 14 ++++
drivers/net/vxlan.c | 14 ++++
include/linux/netdev_features.h | 7 ++
include/linux/netdevice.h | 7 ++
include/linux/skbuff.h | 7 ++
net/core/dev.c | 31 ++++++++
net/core/ethtool.c | 4 +
net/core/skbuff.c | 21 +++++-
net/ipv4/af_inet.c | 20 ++++-
net/ipv4/fou.c | 14 ++++
net/ipv4/gre_offload.c | 37 +++++++++-
net/ipv4/tcp_offload.c | 25 ++++++-
net/ipv4/udp_offload.c | 20 ++++-
net/ipv6/ip6_offload.c | 9 ++
20 files changed, 344 insertions(+), 79 deletions(-)
^ permalink raw reply
* [RFC PATCH 1/9] ipv4/GRO: Allow multiple frames to use the same IP ID
From: Alexander Duyck @ 2016-03-18 23:24 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
In RFC 6864 it is stated that we can essentially ignore the IPv4 ID field
if we have not and will not use fragmentation. Such a frame is defined
as having the DF flag set to 1, and the MF and frag_offset as 0. Currently
for GRO we were requiring that the inner header always have an increasing
IPv4 ID, but we are ignoring the outer value.
This patch is a first step in trying to reverse some of that. Specifically
what this patch does is allow us to coalesce frames that have a static IPv4
ID value. So for example if we had a series of frames where the DF flag
was set we would allow the same IPv4 ID value to be used for all the frames
belonging to that flow. This would become the standard behavior for TCP so
it would support either a fixed IPv4 ID value, or one in which the value
increments.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
include/linux/netdevice.h | 5 ++++-
net/ipv4/af_inet.c | 8 ++++++--
net/ipv4/tcp_offload.c | 15 ++++++++++++++-
3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index be693b34662f..31474d9d8a96 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2113,7 +2113,10 @@ struct napi_gro_cb {
/* Used in foo-over-udp, set in udp[46]_gro_receive */
u8 is_ipv6:1;
- /* 7 bit hole */
+ /* Flag indicating if IP ID can be ignored on receive */
+ u8 rfc6864:1;
+
+ /* 6 bit hole */
/* used to support CHECKSUM_COMPLETE for tunneling protocols */
__wsum csum;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0cc923f83e10..5e3885672907 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1320,6 +1320,8 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
id = ntohl(*(__be32 *)&iph->id);
flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
+
+ NAPI_GRO_CB(skb)->rfc6864 = !!(id & IP_DF);
id >>= 16;
for (p = *head; p; p = p->next) {
@@ -1352,8 +1354,10 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
* This is because some GSO/TSO implementations do not
* correctly increment the IP ID for the outer hdrs.
*/
- NAPI_GRO_CB(p)->flush_id =
- ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
+ NAPI_GRO_CB(p)->flush_id = (u16)(id - ntohs(iph2->id));
+ if (!NAPI_GRO_CB(p)->rfc6864 || !NAPI_GRO_CB(skb)->rfc6864)
+ NAPI_GRO_CB(p)->flush_id ^= NAPI_GRO_CB(p)->count;
+
NAPI_GRO_CB(p)->flush |= flush;
}
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index 773083b7f1e9..1a2e9957c177 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -237,7 +237,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
found:
/* Include the IP ID check below from the inner most IP hdr */
- flush = NAPI_GRO_CB(p)->flush | NAPI_GRO_CB(p)->flush_id;
+ flush = NAPI_GRO_CB(p)->flush;
flush |= (__force int)(flags & TCP_FLAG_CWR);
flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH));
@@ -246,6 +246,19 @@ found:
flush |= *(u32 *)((u8 *)th + i) ^
*(u32 *)((u8 *)th2 + i);
+ /* Some devices may make use of RFC6864 to skip the need to
+ * increment the IP ID on inner headers of tunneled frames. This
+ * allows them to make use of TSO by not updating the headers from
+ * the outer L4 to inner L3. We should be able to identify any such
+ * frames on the second frame received and then after that we expect
+ * the same ID on all remaining frames in the flow.
+ */
+ if ((NAPI_GRO_CB(p)->flush_id == 1) && NAPI_GRO_CB(p)->rfc6864 &&
+ (NAPI_GRO_CB(p)->count == 1))
+ NAPI_GRO_CB(p)->rfc6864 = 0;
+ else
+ flush |= NAPI_GRO_CB(p)->flush_id;
+
mss = skb_shinfo(p)->gso_size;
flush |= (len - 1) >= mss;
^ permalink raw reply related
* [RFC PATCH 2/9] gre: Enforce IP ID verification on outer headers
From: Alexander Duyck @ 2016-03-18 23:24 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This change enforces the IP ID verification on outer headers. As a result
if the DF flag is not set on the outer header we will force the flow to be
flushed in the event that the IP ID is out of sequence with the existing
flow.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
net/ipv4/gre_offload.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 540866dbd27d..7ea14ced9222 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -203,6 +203,20 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
continue;
}
}
+
+ /* Include the IP ID check from the outer IP hdr */
+ if (!NAPI_GRO_CB(p)->flush_id)
+ continue;
+
+ /* If flush_id is non-zero and rfc6864 is enabled for
+ * the new frame the only possibility is that we are
+ * incrementing so we can xor by count to cancel out
+ * the one acceptable value.
+ */
+ NAPI_GRO_CB(p)->flush |= NAPI_GRO_CB(skb)->rfc6864 ?
+ NAPI_GRO_CB(p)->flush_id ^
+ NAPI_GRO_CB(p)->count :
+ NAPI_GRO_CB(p)->flush_id;
}
skb_gro_pull(skb, grehlen);
^ permalink raw reply related
* [RFC PATCH 3/9] geneve: Enforce IP ID verification on outer headers
From: Alexander Duyck @ 2016-03-18 23:24 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This change enforces the IP ID verification on outer headers. As a result
if the DF flag is not set on the outer header we will force the flow to be
flushed in the event that the IP ID is out of sequence with the existing
flow.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/geneve.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 192631a345df..2dac5496c965 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -473,6 +473,20 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
+
+ /* Include the IP ID check from the outer IP hdr */
+ if (!NAPI_GRO_CB(p)->flush_id)
+ continue;
+
+ /* If flush_id is non-zero and rfc6864 is enabled for
+ * the new frame the only possibility is that we are
+ * incrementing so we can xor by count to cancel out
+ * the one acceptable value.
+ */
+ NAPI_GRO_CB(p)->flush |= NAPI_GRO_CB(skb)->rfc6864 ?
+ NAPI_GRO_CB(p)->flush_id ^
+ NAPI_GRO_CB(p)->count :
+ NAPI_GRO_CB(p)->flush_id;
}
type = gh->proto_type;
^ permalink raw reply related
* [RFC PATCH 4/9] vxlan: Enforce IP ID verification on outer headers
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This change enforces the IP ID verification on outer headers. As a result
if the DF flag is not set on the outer header we will force the flow to be
flushed in the event that the IP ID is out of sequence with the existing
flow.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/vxlan.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 800106a7246c..d6838a30e772 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -601,6 +601,20 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
+
+ /* Include the IP ID check from the outer IP hdr */
+ if (!NAPI_GRO_CB(p)->flush_id)
+ continue;
+
+ /* If flush_id is non-zero and rfc6864 is enabled for
+ * the new frame the only possibility is that we are
+ * incrementing so we can xor by count to cancel out
+ * the one acceptable value.
+ */
+ NAPI_GRO_CB(p)->flush |= NAPI_GRO_CB(skb)->rfc6864 ?
+ NAPI_GRO_CB(p)->flush_id ^
+ NAPI_GRO_CB(p)->count :
+ NAPI_GRO_CB(p)->flush_id;
}
pp = eth_gro_receive(head, skb);
^ permalink raw reply related
* [RFC PATCH 5/9] gue: Enforce IP ID verification on outer headers
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This change enforces the IP ID verification on outer headers. As a result
if the DF flag is not set on the outer header we will force the flow to be
flushed in the event that the IP ID is out of sequence with the existing
flow.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
net/ipv4/fou.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 780484243e14..2be35e4f6d88 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -341,6 +341,20 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
+
+ /* Include the IP ID check from the outer IP hdr */
+ if (!NAPI_GRO_CB(p)->flush_id)
+ continue;
+
+ /* If flush_id is non-zero and rfc6864 is enabled for
+ * the new frame the only possibility is that we are
+ * incrementing so we can xor by count to cancel out
+ * the one acceptable value.
+ */
+ NAPI_GRO_CB(p)->flush |= NAPI_GRO_CB(skb)->rfc6864 ?
+ NAPI_GRO_CB(p)->flush_id ^
+ NAPI_GRO_CB(p)->count :
+ NAPI_GRO_CB(p)->flush_id;
}
rcu_read_lock();
^ permalink raw reply related
* [RFC PATCH 6/9] ethtool: Add support for toggling any of the GSO offloads
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
The strings were missing for several of the GSO offloads that are
available. This patch provides the missing strings so that we can toggle
or query any of them via the ethtool command.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
net/core/ethtool.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 2966cd0d7c93..b3c39d531469 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -82,9 +82,12 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
[NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
[NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
+ [NETIF_F_GSO_GRE_CSUM_BIT] = "tx-gre-csum-segmentation",
[NETIF_F_GSO_IPIP_BIT] = "tx-ipip-segmentation",
[NETIF_F_GSO_SIT_BIT] = "tx-sit-segmentation",
[NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
+ [NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
+ [NETIF_F_GSO_TUNNEL_REMCSUM_BIT] = "tx-remcsum-segmentation",
[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp",
^ permalink raw reply related
* [RFC PATCH 7/9] GSO: Support partial segmentation offload
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This patch adds support for something I am referring to as GSO partial.
The basic idea is that we can support a broader range of devices for
segmentation if we use fixed outer headers and have the hardware only
really deal with segmenting the inner header. The idea behind the naming
is due to the fact that everything before csum_start will be fixed headers,
and everything after will be the region that is handled by hardware.
With the current implementation it allows us to add support for the
following GSO types with an inner TSO or TSO6 offload:
NETIF_F_GSO_GRE
NETIF_F_GSO_GRE_CSUM
NETIF_F_UDP_TUNNEL
NETIF_F_UDP_TUNNEL_CSUM
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
include/linux/netdev_features.h | 7 ++++++-
include/linux/netdevice.h | 2 ++
include/linux/skbuff.h | 7 ++++++-
net/core/dev.c | 31 ++++++++++++++++++++++++++++++-
net/core/ethtool.c | 1 +
net/core/skbuff.c | 21 ++++++++++++++++++++-
net/ipv4/af_inet.c | 12 ++++++++++--
net/ipv4/gre_offload.c | 23 +++++++++++++++++++----
net/ipv4/tcp_offload.c | 10 ++++++++--
net/ipv4/udp_offload.c | 20 ++++++++++++++++----
net/ipv6/ip6_offload.c | 9 ++++++++-
11 files changed, 126 insertions(+), 17 deletions(-)
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index a734bf43d190..8df3c5553af0 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -48,8 +48,12 @@ enum {
NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */
NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */
NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */
+ NETIF_F_GSO_PARTIAL_BIT, /* ... Only segment inner-most L4
+ * in hardware and all other
+ * headers in software.
+ */
/**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */
- NETIF_F_GSO_TUNNEL_REMCSUM_BIT,
+ NETIF_F_GSO_PARTIAL_BIT,
NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */
NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */
@@ -121,6 +125,7 @@ enum {
#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM)
#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
+#define NETIF_F_GSO_PARTIAL __NETIF_F(GSO_PARTIAL)
#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 31474d9d8a96..427d748ad8f9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1647,6 +1647,7 @@ struct net_device {
netdev_features_t vlan_features;
netdev_features_t hw_enc_features;
netdev_features_t mpls_features;
+ netdev_features_t gso_partial_features;
int ifindex;
int group;
@@ -4014,6 +4015,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT));
BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT));
BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT));
+ BUILD_BUG_ON(SKB_GSO_PARTIAL != (NETIF_F_GSO_PARTIAL >> NETIF_F_GSO_SHIFT));
return (features & feature) == feature;
}
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 15d0df943466..c291a282f8b6 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -482,6 +482,8 @@ enum {
SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11,
SKB_GSO_TUNNEL_REMCSUM = 1 << 12,
+
+ SKB_GSO_PARTIAL = 1 << 13,
};
#if BITS_PER_LONG > 32
@@ -3584,7 +3586,10 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
* Keeps track of level of encapsulation of network headers.
*/
struct skb_gso_cb {
- int mac_offset;
+ union {
+ int mac_offset;
+ int data_offset;
+ };
int encap_level;
__wsum csum;
__u16 csum_start;
diff --git a/net/core/dev.c b/net/core/dev.c
index edb7179bc051..666cf427898b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2711,6 +2711,19 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
return ERR_PTR(err);
}
+ /* Only report GSO partial support if it will enable us to
+ * support segmentation on this frame without needing additional
+ * work.
+ */
+ if (features & NETIF_F_GSO_PARTIAL) {
+ netdev_features_t partial_features;
+ struct net_device *dev = skb->dev;
+
+ partial_features = dev->features & dev->gso_partial_features;
+ if (!skb_gso_ok(skb, features | partial_features))
+ features &= ~NETIF_F_GSO_PARTIAL;
+ }
+
BUILD_BUG_ON(SKB_SGO_CB_OFFSET +
sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
@@ -2841,6 +2854,14 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
if (skb->encapsulation)
features &= dev->hw_enc_features;
+ /* Support for GSO partial features requires software intervention
+ * before we can actually process the packets so we need to strip
+ * support for any partial features now and we can pull them back
+ * in after we have partially segmented the frame.
+ */
+ if (skb_is_gso(skb) && !(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL))
+ features &= ~dev->gso_partial_features;
+
if (skb_vlan_tagged(skb))
features = netdev_intersect_features(features,
dev->vlan_features |
@@ -6702,6 +6723,14 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
}
}
+ /* GSO partial features require GSO partial be set */
+ if ((features & dev->gso_partial_features) &&
+ !(features & NETIF_F_GSO_PARTIAL)) {
+ netdev_dbg(dev,
+ "Dropping partially supported GSO features since no GSO partial.\n");
+ features &= ~dev->gso_partial_features;
+ }
+
#ifdef CONFIG_NET_RX_BUSY_POLL
if (dev->netdev_ops->ndo_busy_poll)
features |= NETIF_F_BUSY_POLL;
@@ -6982,7 +7011,7 @@ int register_netdevice(struct net_device *dev)
/* Make NETIF_F_SG inheritable to tunnel devices.
*/
- dev->hw_enc_features |= NETIF_F_SG;
+ dev->hw_enc_features |= NETIF_F_SG | NETIF_F_GSO_PARTIAL;
/* Make NETIF_F_SG inheritable to MPLS.
*/
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index b3c39d531469..d1b278c6c29f 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -88,6 +88,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
[NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
[NETIF_F_GSO_TUNNEL_REMCSUM_BIT] = "tx-remcsum-segmentation",
+ [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial",
[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp",
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f044f970f1a6..bdcba77e164c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3076,8 +3076,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
struct sk_buff *frag_skb = head_skb;
unsigned int offset = doffset;
unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
+ unsigned int partial_segs = 0;
unsigned int headroom;
- unsigned int len;
+ unsigned int len = head_skb->len;
__be16 proto;
bool csum;
int sg = !!(features & NETIF_F_SG);
@@ -3094,6 +3095,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
csum = !!can_checksum_protocol(features, proto);
+ /* GSO partial only requires that we trim off any excess that
+ * doesn't fit into an MSS sized block, so take care of that
+ * now.
+ */
+ if (features & NETIF_F_GSO_PARTIAL) {
+ partial_segs = len / mss;
+ mss *= partial_segs;
+ }
+
headroom = skb_headroom(head_skb);
pos = skb_headlen(head_skb);
@@ -3281,6 +3291,15 @@ perform_csum_check:
*/
segs->prev = tail;
+ /* Update GSO info on first skb in partial sequence. */
+ if (partial_segs) {
+ skb_shinfo(segs)->gso_size = mss / partial_segs;
+ skb_shinfo(segs)->gso_segs = partial_segs;
+ skb_shinfo(segs)->gso_type = skb_shinfo(head_skb)->gso_type |
+ SKB_GSO_PARTIAL;
+ SKB_GSO_CB(segs)->data_offset = skb_headroom(segs) + doffset;
+ }
+
/* Following permits correct backpressure, for protocols
* using skb_set_owner_w().
* Idea is to tranfert ownership from head_skb to last segment.
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 5e3885672907..d091f91fa25d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1199,7 +1199,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
unsigned int offset = 0;
bool udpfrag, encap;
struct iphdr *iph;
- int proto;
+ int proto, tot_len;
int nhoff;
int ihl;
int id;
@@ -1269,10 +1269,18 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
if (skb->next)
iph->frag_off |= htons(IP_MF);
offset += skb->len - nhoff - ihl;
+ tot_len = skb->len - nhoff;
+ } else if (skb_is_gso(skb)) {
+ iph->id = htons(id);
+ id += skb_shinfo(skb)->gso_segs;
+ tot_len = skb_shinfo(skb)->gso_size +
+ SKB_GSO_CB(skb)->data_offset +
+ skb->head - (unsigned char *)iph;
} else {
iph->id = htons(id++);
+ tot_len = skb->len - nhoff;
}
- iph->tot_len = htons(skb->len - nhoff);
+ iph->tot_len = htons(tot_len);
ip_send_check(iph);
if (encap)
skb_reset_inner_headers(skb);
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 7ea14ced9222..dea0390d65bb 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -85,7 +85,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
skb = segs;
do {
struct gre_base_hdr *greh;
- __be32 *pcsum;
+ __sum16 *pcsum;
/* Set up inner headers if we are offloading inner checksum */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -105,10 +105,25 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
continue;
greh = (struct gre_base_hdr *)skb_transport_header(skb);
- pcsum = (__be32 *)(greh + 1);
+ pcsum = (__sum16 *)(greh + 1);
+
+ if (skb_is_gso(skb)) {
+ unsigned int partial_adj;
+
+ /* Adjust checksum to account for the fact that
+ * the partial checksum is based on actual size
+ * whereas headers should be based on MSS size.
+ */
+ partial_adj = skb->len + skb_headroom(skb) -
+ SKB_GSO_CB(skb)->data_offset -
+ skb_shinfo(skb)->gso_size;
+ *pcsum = ~csum_fold((__force __wsum)htonl(partial_adj));
+ } else {
+ *pcsum = 0;
+ }
- *pcsum = 0;
- *(__sum16 *)pcsum = gso_make_checksum(skb, 0);
+ *(pcsum + 1) = 0;
+ *pcsum = gso_make_checksum(skb, 0);
} while ((skb = skb->next));
out:
return segs;
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index 1a2e9957c177..4e9b8f011473 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -107,6 +107,12 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
goto out;
}
+ /* GSO partial only requires splitting the frame into an MSS
+ * multiple and possibly a remainder. So update the mss now.
+ */
+ if (features & NETIF_F_GSO_PARTIAL)
+ mss = skb->len - (skb->len % mss);
+
copy_destructor = gso_skb->destructor == tcp_wfree;
ooo_okay = gso_skb->ooo_okay;
/* All segments but the first should have ooo_okay cleared */
@@ -131,7 +137,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
newcheck = ~csum_fold((__force __wsum)((__force u32)th->check +
(__force u32)delta));
- do {
+ while (skb->next) {
th->fin = th->psh = 0;
th->check = newcheck;
@@ -151,7 +157,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
th->seq = htonl(seq);
th->cwr = 0;
- } while (skb->next);
+ }
/* Following permits TCP Small Queues to work well with GSO :
* The callback to TCP stack will be called at the time last frag
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 8a3405a80260..5fcb93269afb 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -100,7 +100,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
udp_offset = outer_hlen - tnl_hlen;
skb = segs;
do {
- __be16 len;
+ unsigned int len;
if (remcsum)
skb->ip_summed = CHECKSUM_NONE;
@@ -118,14 +118,26 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len);
skb_set_transport_header(skb, udp_offset);
- len = htons(skb->len - udp_offset);
+ len = skb->len - udp_offset;
uh = udp_hdr(skb);
- uh->len = len;
+
+ /* If we are only performing partial GSO the inner header
+ * will be using a length value equal to only one MSS sized
+ * segment instead of the entire frame.
+ */
+ if (skb_is_gso(skb)) {
+ uh->len = htons(skb_shinfo(skb)->gso_size +
+ SKB_GSO_CB(skb)->data_offset +
+ skb->head - (unsigned char *)uh);
+ } else {
+ uh->len = htons(len);
+ }
if (!need_csum)
continue;
- uh->check = ~csum_fold(csum_add(partial, (__force __wsum)len));
+ uh->check = ~csum_fold(csum_add(partial,
+ (__force __wsum)htonl(len)));
if (skb->encapsulation || !offload_csum) {
uh->check = gso_make_checksum(skb, ~uh->check);
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index eeca943f12dc..d467053c226a 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -63,6 +63,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
int proto;
struct frag_hdr *fptr;
unsigned int unfrag_ip6hlen;
+ unsigned int payload_len;
u8 *prevhdr;
int offset = 0;
bool encap, udpfrag;
@@ -117,7 +118,13 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
for (skb = segs; skb; skb = skb->next) {
ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff);
- ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h));
+ if (skb_is_gso(skb))
+ payload_len = skb_shinfo(skb)->gso_size +
+ SKB_GSO_CB(skb)->data_offset +
+ skb->head - (unsigned char *)(ipv6h + 1);
+ else
+ payload_len = skb->len - nhoff - sizeof(*ipv6h);
+ ipv6h->payload_len = htons(payload_len);
skb->network_header = (u8 *)ipv6h - skb->head;
if (udpfrag) {
^ permalink raw reply related
* [RFC PATCH 8/9] i40e/i40evf: Add support for GSO partial with UDP_TUNNEL_CSUM and GRE_CSUM
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This patch makes it so that i40e and i40evf can use GSO_PARTIAL to support
segmentation for frames with checksums enabled in outer headers. As a
result we can now send data over these types of tunnels at over 20Gb/s
versus the 12Gb/s that was previously possible on my system.
The advantage with the i40e parts is that this offload is mostly
transparent as the hardware still deals with the inner and/or outer IPv4
headers so the IP ID is still incrementing for both when this offload is
performed.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/i40e/i40e_main.c | 8 +++++++-
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 14 +++++++++++---
drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 14 +++++++++++---
drivers/net/ethernet/intel/i40evf/i40evf_main.c | 8 +++++++-
4 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 39b0009253c2..ac3964a9f5c0 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -9050,6 +9050,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_TSO6 |
NETIF_F_TSO_ECN |
NETIF_F_GSO_GRE |
+ NETIF_F_GSO_GRE_CSUM |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
0;
@@ -9074,7 +9075,12 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
netdev->features |= NETIF_F_NTUPLE;
if (pf->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE)
- netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ netdev->features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ else
+ netdev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
+ netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
+ netdev->features |= NETIF_F_GSO_PARTIAL | netdev->gso_partial_features;
/* copy netdev features into list of user selectable features */
netdev->hw_features |= netdev->features;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 5d5fa5359a1d..50aa76d7f92e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2297,9 +2297,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
ip.v6->payload_len = 0;
}
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE |
+ SKB_GSO_GRE_CSUM |
+ SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM)) {
- if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL |
+ SKB_GSO_UDP_TUNNEL_CSUM))
+ l4.udp->len = 0;
+
+ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
@@ -2470,7 +2477,8 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
/* indicate if we need to offload outer UDP header */
if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
- (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+ (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) &&
+ !(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL))
tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
/* record tunnel offload values */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index 04aabc52ba0d..1bb7c3efa36c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -1564,9 +1564,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
ip.v6->payload_len = 0;
}
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE |
+ SKB_GSO_GRE_CSUM |
+ SKB_GSO_UDP_TUNNEL |
SKB_GSO_UDP_TUNNEL_CSUM)) {
- if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL |
+ SKB_GSO_UDP_TUNNEL_CSUM))
+ l4.udp->len = 0;
+
+ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) {
/* determine offset of outer transport header */
l4_offset = l4.hdr - skb->data;
@@ -1695,7 +1702,8 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
/* indicate if we need to offload outer UDP header */
if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
- (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+ (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) &&
+ !(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL))
tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
/* record tunnel offload values */
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index e3973684746b..ed3c9310c3e0 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -2331,7 +2331,7 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_TSO_ECN |
- NETIF_F_GSO_GRE |
+ NETIF_F_GSO_GRE |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_RXCSUM |
NETIF_F_GRO;
@@ -2342,11 +2342,17 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
NETIF_F_TSO6 |
NETIF_F_TSO_ECN |
NETIF_F_GSO_GRE |
+ NETIF_F_GSO_GRE_CSUM |
NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM;
if (adapter->flags & I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE)
netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
+ else
+ netdev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
+ netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
+ netdev->features |= NETIF_F_GSO_PARTIAL | netdev->gso_partial_features;
/* copy netdev features into list of user selectable features */
netdev->hw_features |= netdev->features;
^ permalink raw reply related
* [RFC PATCH 9/9] ixgbe/ixgbevf: Add support for GSO partial
From: Alexander Duyck @ 2016-03-18 23:25 UTC (permalink / raw)
To: ecree, netdev, davem, alexander.duyck, tom
In-Reply-To: <20160318230945.14955.63211.stgit@localhost.localdomain>
This patch adds support for partial GSO segmentation in the case of GRE or
UDP encapsulated frames.
The one bit in this patch that is a bit controversial is the fact that we
are leaving the inner IPv4 IP ID as a static value in the case of
segmentation. As per RFC6864 this should be acceptable as TCP frames set
the DF bit so the IP ID should be ignored. However this is not always the
case as header compression schemes for PPP and SLIP can end up taking a
performance hit as they have to record the fact that the ID didn't change
as expected.
In addition GRO was examining the IP ID field as well. As such on older
GRO implementations TSO frames from this driver may end up blocking GRO on
the other end which will likely hurt performance instead of helping it.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 72 +++++++++++++-------
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 77 ++++++++++++++-------
2 files changed, 99 insertions(+), 50 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 59b43ce200be..bef69306fb65 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7178,9 +7178,18 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
struct ixgbe_tx_buffer *first,
u8 *hdr_len)
{
+ u32 vlan_macip_lens, type_tucmd, mss_l4len_idx;
struct sk_buff *skb = first->skb;
- u32 vlan_macip_lens, type_tucmd;
- u32 mss_l4len_idx, l4len;
+ union {
+ struct iphdr *v4;
+ struct ipv6hdr *v6;
+ unsigned char *hdr;
+ } ip;
+ union {
+ struct tcphdr *tcp;
+ unsigned char *hdr;
+ } l4;
+ u32 paylen, l4_offset;
int err;
if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -7193,46 +7202,52 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
if (err < 0)
return err;
+ ip.hdr = skb_network_header(skb);
+ l4.hdr = skb_checksum_start(skb);
+
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
- if (first->protocol == htons(ETH_P_IP)) {
- struct iphdr *iph = ip_hdr(skb);
- iph->tot_len = 0;
- iph->check = 0;
- tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP,
- 0);
+ /* initialize outer IP header fields */
+ if (ip.v4->version == 4) {
+ /* IP header will have to cancel out any data that
+ * is not a part of the outer IP header
+ */
+ ip.v4->check = csum_fold(csum_add(lco_csum(skb),
+ csum_unfold(l4.tcp->check)));
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+ ip.v4->tot_len = 0;
first->tx_flags |= IXGBE_TX_FLAGS_TSO |
IXGBE_TX_FLAGS_CSUM |
IXGBE_TX_FLAGS_IPV4;
- } else if (skb_is_gso_v6(skb)) {
- ipv6_hdr(skb)->payload_len = 0;
- tcp_hdr(skb)->check =
- ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0);
+ } else {
+ ip.v6->payload_len = 0;
first->tx_flags |= IXGBE_TX_FLAGS_TSO |
IXGBE_TX_FLAGS_CSUM;
}
- /* compute header lengths */
- l4len = tcp_hdrlen(skb);
- *hdr_len = skb_transport_offset(skb) + l4len;
+ /* determine offset of inner transport header */
+ l4_offset = l4.hdr - skb->data;
+
+ /* compute length of segmentation header */
+ *hdr_len = (l4.tcp->doff * 4) + l4_offset;
+
+ /* remove payload length from inner checksum */
+ paylen = skb->len - l4_offset;
+ csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
/* update gso size and bytecount with header size */
first->gso_segs = skb_shinfo(skb)->gso_segs;
first->bytecount += (first->gso_segs - 1) * *hdr_len;
/* mss_l4len_id: use 0 as index for TSO */
- mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
+ mss_l4len_idx = (*hdr_len - l4_offset) << IXGBE_ADVTXD_L4LEN_SHIFT;
mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
- vlan_macip_lens = skb_network_header_len(skb);
- vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
+ vlan_macip_lens = l4.hdr - ip.hdr;
+ vlan_macip_lens |= (ip.hdr - skb->data) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0, type_tucmd,
@@ -9201,6 +9216,14 @@ skip_sriov:
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
+ netdev->gso_partial_features = NETIF_F_GSO_GRE |
+ NETIF_F_GSO_GRE_CSUM |
+ NETIF_F_GSO_UDP_TUNNEL |
+ NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
+ netdev->features |= NETIF_F_GSO_PARTIAL |
+ netdev->gso_partial_features;
+
if (hw->mac.type >= ixgbe_mac_82599EB)
netdev->features |= NETIF_F_SCTP_CRC;
@@ -9219,7 +9242,10 @@ skip_sriov:
NETIF_F_SCTP_CRC;
netdev->mpls_features |= NETIF_F_HW_CSUM;
- netdev->hw_enc_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM |
+ netdev->gso_partial_features;
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 0c3e29b55b45..1ece15ee9834 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -3272,9 +3272,18 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
struct ixgbevf_tx_buffer *first,
u8 *hdr_len)
{
+ u32 vlan_macip_lens, type_tucmd, mss_l4len_idx;
struct sk_buff *skb = first->skb;
- u32 vlan_macip_lens, type_tucmd;
- u32 mss_l4len_idx, l4len;
+ union {
+ struct iphdr *v4;
+ struct ipv6hdr *v6;
+ unsigned char *hdr;
+ } ip;
+ union {
+ struct tcphdr *tcp;
+ unsigned char *hdr;
+ } l4;
+ u32 paylen, l4_offset;
int err;
if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -3287,49 +3296,53 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
if (err < 0)
return err;
+ ip.hdr = skb_network_header(skb);
+ l4.hdr = skb_checksum_start(skb);
+
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
- if (first->protocol == htons(ETH_P_IP)) {
- struct iphdr *iph = ip_hdr(skb);
-
- iph->tot_len = 0;
- iph->check = 0;
- tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP,
- 0);
+ /* initialize outer IP header fields */
+ if (ip.v4->version == 4) {
+ /* IP header will have to cancel out any data that
+ * is not a part of the outer IP header
+ */
+ ip.v4->check = csum_fold(csum_add(lco_csum(skb),
+ csum_unfold(l4.tcp->check)));
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+ ip.v4->tot_len = 0;
first->tx_flags |= IXGBE_TX_FLAGS_TSO |
IXGBE_TX_FLAGS_CSUM |
IXGBE_TX_FLAGS_IPV4;
- } else if (skb_is_gso_v6(skb)) {
- ipv6_hdr(skb)->payload_len = 0;
- tcp_hdr(skb)->check =
- ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0);
+ } else {
+ ip.v6->payload_len = 0;
first->tx_flags |= IXGBE_TX_FLAGS_TSO |
IXGBE_TX_FLAGS_CSUM;
}
- /* compute header lengths */
- l4len = tcp_hdrlen(skb);
- *hdr_len += l4len;
- *hdr_len = skb_transport_offset(skb) + l4len;
+ /* determine offset of inner transport header */
+ l4_offset = l4.hdr - skb->data;
- /* update GSO size and bytecount with header size */
+ /* compute length of segmentation header */
+ *hdr_len = (l4.tcp->doff * 4) + l4_offset;
+
+ /* remove payload length from inner checksum */
+ paylen = skb->len - l4_offset;
+ csum_replace_by_diff(&l4.tcp->check, htonl(paylen));
+
+ /* update gso size and bytecount with header size */
first->gso_segs = skb_shinfo(skb)->gso_segs;
first->bytecount += (first->gso_segs - 1) * *hdr_len;
/* mss_l4len_id: use 1 as index for TSO */
- mss_l4len_idx = l4len << IXGBE_ADVTXD_L4LEN_SHIFT;
+ mss_l4len_idx = (*hdr_len - l4_offset) << IXGBE_ADVTXD_L4LEN_SHIFT;
mss_l4len_idx |= skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT;
mss_l4len_idx |= 1 << IXGBE_ADVTXD_IDX_SHIFT;
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
- vlan_macip_lens = skb_network_header_len(skb);
- vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
+ vlan_macip_lens = l4.hdr - ip.hdr;
+ vlan_macip_lens |= (ip.hdr - skb->data) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens,
@@ -3992,12 +4005,19 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_sw_init;
}
+ netdev->gso_partial_features = NETIF_F_GSO_GRE |
+ NETIF_F_GSO_GRE_CSUM |
+ NETIF_F_GSO_UDP_TUNNEL |
+ NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
netdev->hw_features = NETIF_F_SG |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXCSUM |
NETIF_F_HW_CSUM |
- NETIF_F_SCTP_CRC;
+ NETIF_F_SCTP_CRC |
+ NETIF_F_GSO_PARTIAL |
+ netdev->gso_partial_features;
netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_CTAG_TX |
@@ -4011,7 +4031,10 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_SCTP_CRC;
netdev->mpls_features |= NETIF_F_HW_CSUM;
- netdev->hw_enc_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM |
+ netdev->gso_partial_features;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
^ permalink raw reply related
* Re: [PATCH net-next v2 0/4] ldmvsw: Add ldmvsw driver
From: David Miller @ 2016-03-18 23:33 UTC (permalink / raw)
To: Aaron.Young
Cc: netdev, sowmini.varadhan, alexandre.chartre, rashmi.narasimhan,
atish.patra
In-Reply-To: <cover.1458006737.git.Aaron.Young@oracle.com>
From: Aaron Young <Aaron.Young@oracle.com>
Date: Tue, 15 Mar 2016 11:35:36 -0700
> This series adds a new Logical Domains vSwitch (ldmvsw) driver.
Series applied, thanks Aaron.
^ permalink raw reply
* Re: [PATCH net-next] cls_bpf: reset class and reuse major in da
From: David Miller @ 2016-03-18 23:35 UTC (permalink / raw)
To: daniel; +Cc: alexei.starovoitov, netdev
In-Reply-To: <9e700a6f163815e6f79db50e7a8f9f52696f28e7.1458075641.git.daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Tue, 15 Mar 2016 22:41:22 +0100
> There are two issues with the current code. First one is that we need
> to set res->class to 0 in case we use non-default classid matching.
>
> This is important for the case where cls_bpf was initially set up with
> an optional binding to a default class with tcf_bind_filter(), where
> the underlying qdisc implements bind_tcf() that fills res->class and
> tests for it later on when doing the classification. Convention for
> these cases is that after tc_classify() was called, such qdiscs (atm,
> drr, qfq, cbq, hfsc, htb) first test class, and if 0, then they lookup
> based on classid.
>
> Second, there's a bug with da mode, where res->classid is only assigned
> a 16 bit minor, but it needs to expand to the full 32 bit major/minor
> combination instead, therefore we need to expand with the bound major.
> This is fine as classes belonging to a classful qdisc must share the
> same major.
>
> Fixes: 045efa82ff56 ("cls_bpf: introduce integrated actions")
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Acked-by: Alexei Starovoitov <ast@kernel.org>
Applied, thanks Daniel.
^ permalink raw reply
* Re: [PATCH] net: mvneta: bm: clarify dependencies
From: David Miller @ 2016-03-18 23:37 UTC (permalink / raw)
To: arnd; +Cc: netdev, gregory.clement, mw, linux-kernel
In-Reply-To: <1458078449-635940-1-git-send-email-arnd@arndb.de>
From: Arnd Bergmann <arnd@arndb.de>
Date: Tue, 15 Mar 2016 22:47:14 +0100
> MVNETA_BM has a dependency on MVNETA, so we can only select the former
> if the latter is enabled. However, the code dependency is the reverse:
> The mvneta module can call into the mvneta_bm module, so mvneta cannot
> be a built-in if mvneta_bm is a module, or we get a link error:
>
> drivers/net/built-in.o: In function `mvneta_remove':
> drivers/net/ethernet/marvell/mvneta.c:4211: undefined reference to `mvneta_bm_pool_destroy'
> drivers/net/built-in.o: In function `mvneta_bm_update_mtu':
> drivers/net/ethernet/marvell/mvneta.c:1034: undefined reference to `mvneta_bm_bufs_free'
>
> This avoids the problem by further clarifying the dependency so that
> MVNETA_BM is a silent Kconfig option that gets turned on by the
> new MVNETA_BM_ENABLE option. This way both the core HWBM module and
> the MVNETA_BM code are always built-in when needed.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Fixes: dc35a10f68d3 ("net: mvneta: bm: add support for hardware buffer management")
Applied.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox