Netdev List
 help / color / mirror / Atom feed
* Re: [v6 PATCH 1/8] cxgb4/cxgb4vf: Chelsio FCoE offload driver submission (common header updates).
From: James Bottomley @ 2012-11-14  2:26 UTC (permalink / raw)
  To: Naresh Kumar Inna; +Cc: linux-scsi, dm, leedom, netdev, chethan
In-Reply-To: <1351158621-32222-2-git-send-email-naresh@chelsio.com>

On Thu, 2012-10-25 at 15:20 +0530, Naresh Kumar Inna wrote:
> This patch contains updates to firmware/hardware header files shared
> between csiostor and cxgb4/cxgb4vf, and the resulting changes to the
> cxgb4/cxgb4vf source files.
> 
> Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
> ---
>  drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |    8 ++--
>  drivers/net/ethernet/chelsio/cxgb4/sge.c        |    6 ++--
>  drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |   20 +++++-----
>  drivers/net/ethernet/chelsio/cxgb4/t4_msg.h     |    1 +
>  drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |   36 +++++++++++++++++++-
>  drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |   41 ++++++++++++++++++++---
>  drivers/net/ethernet/chelsio/cxgb4vf/sge.c      |    8 ++--
>  7 files changed, 92 insertions(+), 28 deletions(-)

This still doesn't compile:

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c: In function ‘adap_init0’:
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c:3932:10: error: ‘struct fw_caps_config_cmd’ has no member named ‘retval_len16’
make[5]: *** [drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.o] Error 1

James

^ permalink raw reply

* Re: [PATCH V3] wanrouter: Remove it and the drivers that depend on it
From: Paul Gortmaker @ 2012-11-14  6:08 UTC (permalink / raw)
  To: David Miller; +Cc: joe, netdev
In-Reply-To: <20121113.204437.197646115673556624.davem@davemloft.net>

[Re: [PATCH V3] wanrouter: Remove it and the drivers that depend on it] On 13/11/2012 (Tue 20:44) David Miller wrote:

> 
> Paul, you can't have HTML content to the list and one of your MIME
> sections was HTML, so it was rejected by vger's filters.
> 
> Please repost with the HTML stuff removed.

Ah crap.  I'd replied via gmail ; today and occasionally in the past as
a convenient short cut when not reading netdev with a "normal" MUA.  And
this is not the 1st time gmail has randomly decided to be "helpful" by
mangling plain text like this.  Well, I'll be having no more of that BS.

Sorry about that; I know you don't need the extra stupidity to deal
with, esp. at this point in time.  Original plain text follows, courtesy
of reliable 1990's MUA technology -- the pull details remain unchanged.

Paul.
--

On Tue, Nov 13, 2012 at 6:22 PM, David Miller <davem@davemloft.net> wrote:

>From: Joe Perches <joe@perches.com>
>Date: Tue, 13 Nov 2012 14:36:04 -0800

>> Remove wanrouter as it's obsolete and has not been updated
>> by sangoma since 2.4.3 or so and it's not used anymore.
>>
>> Remove obsolete cyclomx drivers.
>> Update files that include now deleted wanrouter bits.
>>
>> Signed-off-by: Joe Perches <joe@perches.com>

>This breaks the build.

>drivers/isdn/i4l/isdn_x25iface.c:33:18: error: field ‘state’ has incomplete type
>drivers/isdn/i4l/isdn_x25iface.c: In function ‘isdn_x25iface_proto_new’:
>drivers/isdn/i4l/isdn_x25iface.c:89:16: error: ‘WAN_UNCONFIGURED’ undeclared (first use in this function)

[...]

I'd hate to see a garbage collection miss out from integration due to
wider testing, so I've taken Joe's commit, put it on today's net-next
and made the following changes:

  -keep magic number references but mark them obsolete (nobody asked for
   this, but it made sense to me).

  -keep the wanrouter.h (uapi and kernel-centric one) files, but with
   only the X.25 bits that caused build failures.  I have trimmed the enum
   to just the bits that were used.  Obvious build failures like davem
   reported aside, I was concerned that userspace might reference the
   headers (got caught on this for my token-ring deletion).  I did not find
   any userspace uses, but it was packaged with most distro's libc header
   content, so who knows?  As I did run into this with the token ring
   delete, so this is the safer route here -- i.e. leaving a skeleton
   header.

I don't want to spam everyone with another giant patch, so note that a
diff from Joe's original and my amendment is shown below (warning - cut
and paste damaged ; not that anyone sane should, but don't try and apply
this delta; it is for review purposes only -- and all lines with "+" are
just restoration of what lines were already there).

For the folks well adapted to git already, I've pushed an equivalent
branch that I have done the build testing of an x86_64 allyesconfig and
allmodconfig, and they compile OK.  This is based on the net-next of
today:

The following changes since commit bf0098f22ca7b59e8844ac6882bbae230d34b98d:

  ARM: net: bpf_jit_32: add VLAN instructions for BPF JIT (2012-11-13 18:21:10 -0500)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux.git wanrouter-delete

for you to fetch changes up to 148233ec812733b88ad4d341a07e23229ed02810:

  wanrouter: Remove it and the drivers that depend on it (2012-11-13 19:53:15 -0500)

----------------------------------------------------------------
Joe Perches (1):
      wanrouter: Remove it and the drivers that depend on it

 Documentation/ioctl/ioctl-number.txt |    2 +-
 Documentation/magic-number.txt       |    2 +-
 Documentation/zh_CN/magic-number.txt |    2 +-
 drivers/isdn/i4l/isdn_x25iface.h     |    1 -
 drivers/net/wan/Kconfig              |   54 --
 drivers/net/wan/Makefile             |    5 -
 drivers/net/wan/cycx_drv.c           |  569 ------------
 drivers/net/wan/cycx_main.c          |  346 --------
 drivers/net/wan/cycx_x25.c           | 1602 ----------------------------------
 include/linux/cyclomx.h              |   77 --
 include/linux/cycx_drv.h             |   64 --
 include/linux/wanrouter.h            |  127 +--
 include/uapi/linux/Kbuild            |    1 -
 include/uapi/linux/wanrouter.h       |  443 +---------
 net/Kconfig                          |    1 -
 net/Makefile                         |    1 -
 net/socket.c                         |    1 -
 net/wanrouter/Kconfig                |   27 -
 net/wanrouter/Makefile               |    7 -
 net/wanrouter/patchlevel             |    1 -
 net/wanrouter/wanmain.c              |  782 -----------------
 net/wanrouter/wanproc.c              |  380 --------
 22 files changed, 11 insertions(+), 4484 deletions(-)
 delete mode 100644 drivers/net/wan/cycx_drv.c
 delete mode 100644 drivers/net/wan/cycx_main.c
 delete mode 100644 drivers/net/wan/cycx_x25.c
 delete mode 100644 include/linux/cyclomx.h
 delete mode 100644 include/linux/cycx_drv.h
 delete mode 100644 net/wanrouter/Kconfig
 delete mode 100644 net/wanrouter/Makefile
 delete mode 100644 net/wanrouter/patchlevel
 delete mode 100644 net/wanrouter/wanmain.c
 delete mode 100644 net/wanrouter/wanproc.c

 -- below not for application, review only ; delta diff follows --

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 028a034..bb8315a 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -179,6 +179,7 @@ Code  Seq#(hex)     Include File            Comments

 'V'    C0      media/davinci/vpfe_capture.h    conflict!
 'V'    C0      media/si4713.h          conflict!
 'W'    00-1F   linux/watchdog.h        conflict!
+'W'    00-1F   linux/wanrouter.h       conflict!               (pre 3.8)

 'W'    00-3F   sound/asound.h          conflict!
 'X'    all     fs/xfs/xfs_fs.h         conflict!
                and fs/xfs/linux-2.6/xfs_ioctl32.h
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index 0c39e72..851e447 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -122,6 +122,7 @@ SLAB_C_MAGIC          0x4f17a36d  kmem_cache        mm/slab.c

 COW_MAGIC             0x4f4f4f4d  cow_header_v1     arch/um/drivers/ubd_user.c
 I810_CARD_MAGIC       0x5072696E  i810_card         sound/oss/i810_audio.c
 TRIDENT_CARD_MAGIC    0x5072696E  trident_card      sound/oss/trident.c
+ROUTER_MAGIC          0x524d4157  wan_device        [in wanrouter.h pre 3.8]

 SCC_MAGIC             0x52696368  gs_port           drivers/char/scc.h
 SAVEKMSG_MAGIC1       0x53415645  savekmsg          arch/*/amiga/config.c
 GDA_MAGIC             0x58464552  gda               arch/mips/include/asm/sn/gda.h
diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt
index 51b7e15..5ab5271 100644
--- a/Documentation/zh_CN/magic-number.txt
+++ b/Documentation/zh_CN/magic-number.txt
@@ -122,6 +122,7 @@ SLAB_C_MAGIC          0x4f17a36d  kmem_cache        mm/slab.c

 COW_MAGIC             0x4f4f4f4d  cow_header_v1     arch/um/drivers/ubd_user.c
 I810_CARD_MAGIC       0x5072696E  i810_card         sound/oss/i810_audio.c
 TRIDENT_CARD_MAGIC    0x5072696E  trident_card      sound/oss/trident.c
+ROUTER_MAGIC          0x524d4157  wan_device        [in wanrouter.h pre 3.8]

 SCC_MAGIC             0x52696368  gs_port           drivers/char/scc.h
 SAVEKMSG_MAGIC1       0x53415645  savekmsg          arch/*/amiga/config.c
 GDA_MAGIC             0x58464552  gda               arch/mips/include/asm/sn/gda.h
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
index d00c86d..e2d4e58 100644
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -21,6 +21,7 @@

 #include <linux/netdevice.h>
 #include <linux/concap.h>
 #include <linux/slab.h>
+#include <linux/wanrouter.h>
 #include <net/x25device.h>
 #include "isdn_x25iface.h"
 
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
new file mode 100644
index 0000000..8198a63
--- /dev/null
+++ b/include/linux/wanrouter.h
@@ -0,0 +1,10 @@
+/*
+ * wanrouter.h Legacy declarations kept around until X25 is removed
+ */
+
+#ifndef        _ROUTER_H
+#define        _ROUTER_H
+
+#include <uapi/linux/wanrouter.h>
+
+#endif /* _ROUTER_H */
diff --git a/include/uapi/linux/wanrouter.h b/include/uapi/linux/wanrouter.h
new file mode 100644
index 0000000..498d6c1
--- /dev/null
+++ b/include/uapi/linux/wanrouter.h
@@ -0,0 +1,17 @@
+/*
+ * wanrouter.h Legacy declarations kept around until X25 is removed
+ */
+
+#ifndef _UAPI_ROUTER_H
+#define _UAPI_ROUTER_H
+
+/* 'state' defines */
+enum wan_states
+{
+       WAN_UNCONFIGURED,       /* link/channel is not configured */
+       WAN_DISCONNECTED,       /* link/channel is disconnected */
+       WAN_CONNECTING,         /* connection is in progress */
+       WAN_CONNECTED           /* link/channel is operational */
+};
+
+#endif /* _UAPI_ROUTER_H */

^ permalink raw reply related

* Re: [3.0.y, 3.2.y, 3.4.y] Re: [PATCH 2/2] [sky2] Fix for interrupt handler
From: Ben Hutchings @ 2012-11-14  5:49 UTC (permalink / raw)
  To: David Miller; +Cc: jrnieder, jdg, mlindner, shemminger, netdev, stable
In-Reply-To: <20121113.031446.1481052044099452015.davem@davemloft.net>

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

On Tue, 2012-11-13 at 03:14 -0500, David Miller wrote:
> From: Jonathan Nieder <jrnieder@gmail.com>
> Date: Sat, 3 Nov 2012 03:04:48 -0700
> 
> > On October 25, Jonathan Nieder wrote:
> >> Mirko Lindner wrote:
> > 
> >>> Re-enable interrupts if it is not our interrupt
> >>>
> >>> Signed-off-by: Mirko Lindner <mlindner@marvell.com>
> > [...]
> >> Tested-by: Julian Gilbey <jdg@debian.org> # 3.2.y, Inspiron 1545
> > 
> > Ping.  Dave, is
> > 
> >   d663d181b9e9 sky2: Fix for interrupt handler
> > 
> > a candidate for inclusion in 3.0-, 3.2-, and 3.4-stable?  (It was
> > applied upstream during the 3.6 merge window.)  I don't see it in
> > the list at [2].
> 
> This looks fine.

Queued up for 3.2, thanks all.

Ben.

-- 
Ben Hutchings
friends: People who know you well, but like you anyway.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* [PATCH] drivers/net: fix tasklet misuse issue
From: Xiaotian Feng @ 2012-11-14  5:47 UTC (permalink / raw)
  To: davem; +Cc: Xiaotian Feng, Xiaotian Feng, netdev, linux-kernel

In commit 175c0dff, drivers uses tasklet_kill to avoid put disabled tasklet
on the tasklet vec. But some of the drivers uses tasklet_init & tasklet_disable
in the driver init code, then tasklet_enable when it is opened. This makes
tasklet_enable on a killed tasklet and make ksoftirqd crazy then. Normally,
drivers should use tasklet_init/tasklet_kill on device open/remove, and use
tasklet_disable/tasklet_enable on device suspend/resume.

Reported-by: Peter Wu <lekensteyn@gmail.com>
Tested-by: Peter Wu <lekensteyn@gmail.com>
Signed-off-by: Xiaotian Feng <dannyfeng@tencent.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org 
---
 drivers/net/ethernet/jme.c                        |   28 ++++++---------------
 drivers/net/ethernet/micrel/ksz884x.c             |   16 +++---------
 drivers/net/ethernet/xilinx/xilinx_axienet_main.c |   12 ++++-----
 3 files changed, 18 insertions(+), 38 deletions(-)

diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 92317e9..c0314c1 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1860,10 +1860,14 @@ jme_open(struct net_device *netdev)
 	jme_clear_pm(jme);
 	JME_NAPI_ENABLE(jme);
 
-	tasklet_enable(&jme->linkch_task);
-	tasklet_enable(&jme->txclean_task);
-	tasklet_hi_enable(&jme->rxclean_task);
-	tasklet_hi_enable(&jme->rxempty_task);
+	tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->rxclean_task, jme_rx_clean_tasklet,
+		     (unsigned long) jme);
+	tasklet_init(&jme->rxempty_task, jme_rx_empty_tasklet,
+		     (unsigned long) jme);
 
 	rc = jme_request_irq(jme);
 	if (rc)
@@ -3079,22 +3083,6 @@ jme_init_one(struct pci_dev *pdev,
 	tasklet_init(&jme->pcc_task,
 		     jme_pcc_tasklet,
 		     (unsigned long) jme);
-	tasklet_init(&jme->linkch_task,
-		     jme_link_change_tasklet,
-		     (unsigned long) jme);
-	tasklet_init(&jme->txclean_task,
-		     jme_tx_clean_tasklet,
-		     (unsigned long) jme);
-	tasklet_init(&jme->rxclean_task,
-		     jme_rx_clean_tasklet,
-		     (unsigned long) jme);
-	tasklet_init(&jme->rxempty_task,
-		     jme_rx_empty_tasklet,
-		     (unsigned long) jme);
-	tasklet_disable_nosync(&jme->linkch_task);
-	tasklet_disable_nosync(&jme->txclean_task);
-	tasklet_disable_nosync(&jme->rxclean_task);
-	tasklet_disable_nosync(&jme->rxempty_task);
 	jme->dpi.cur = PCC_P1;
 
 	jme->reg_ghc = 0;
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index e558edd..b66b285 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -5459,8 +5459,10 @@ static int prepare_hardware(struct net_device *dev)
 	rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
 	if (rc)
 		return rc;
-	tasklet_enable(&hw_priv->rx_tasklet);
-	tasklet_enable(&hw_priv->tx_tasklet);
+	tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
+		     (unsigned long) hw_priv);
+	tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
+		     (unsigned long) hw_priv);
 
 	hw->promiscuous = 0;
 	hw->all_multi = 0;
@@ -7033,16 +7035,6 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
 	spin_lock_init(&hw_priv->hwlock);
 	mutex_init(&hw_priv->lock);
 
-	/* tasklet is enabled. */
-	tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
-		(unsigned long) hw_priv);
-	tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
-		(unsigned long) hw_priv);
-
-	/* tasklet_enable will decrement the atomic counter. */
-	tasklet_disable(&hw_priv->rx_tasklet);
-	tasklet_disable(&hw_priv->tx_tasklet);
-
 	for (i = 0; i < TOTAL_PORT_NUM; i++)
 		init_waitqueue_head(&hw_priv->counter[i].counter);
 
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1d04754..7740f4b 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -942,6 +942,10 @@ static int axienet_open(struct net_device *ndev)
 		phy_start(lp->phy_dev);
 	}
 
+	/* Enable tasklets for Axi DMA error handling */
+	tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
+		     (unsigned long) lp);
+
 	/* Enable interrupts for Axi DMA Tx */
 	ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
 	if (ret)
@@ -950,8 +954,7 @@ static int axienet_open(struct net_device *ndev)
 	ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
 	if (ret)
 		goto err_rx_irq;
-	/* Enable tasklets for Axi DMA error handling */
-	tasklet_enable(&lp->dma_err_tasklet);
+
 	return 0;
 
 err_rx_irq:
@@ -960,6 +963,7 @@ err_tx_irq:
 	if (lp->phy_dev)
 		phy_disconnect(lp->phy_dev);
 	lp->phy_dev = NULL;
+	tasklet_kill(&lp->dma_err_tasklet);
 	dev_err(lp->dev, "request_irq() failed\n");
 	return ret;
 }
@@ -1613,10 +1617,6 @@ static int __devinit axienet_of_probe(struct platform_device *op)
 		goto err_iounmap_2;
 	}
 
-	tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
-		     (unsigned long) lp);
-	tasklet_disable(&lp->dma_err_tasklet);
-
 	return 0;
 
 err_iounmap_2:
-- 
1.7.9.6 (Apple Git-31.1)

^ permalink raw reply related

* RE: 82571EB: Detected Hardware Unit Hang
From: Dave, Tushar N @ 2012-11-14  3:45 UTC (permalink / raw)
  To: Joe Jin
  Cc: e1000-devel@lists.sf.net, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Mary Mcgrath
In-Reply-To: <50A30656.6090508@oracle.com>

>-----Original Message-----
>From: Joe Jin [mailto:joe.jin@oracle.com]
>Sent: Tuesday, November 13, 2012 6:48 PM
>To: Dave, Tushar N
>Cc: e1000-devel@lists.sf.net; netdev@vger.kernel.org; linux-
>kernel@vger.kernel.org; Mary Mcgrath
>Subject: Re: 82571EB: Detected Hardware Unit Hang
>
>On 11/09/12 04:35, Dave, Tushar N wrote:
>> All devices in path from root complex to 82571, should have *same* max
>payload size otherwise it can cause hang.
>> Can you double check this?
>
>Hi Tushar,
>
>Checked with hardware vendor and they said no way to modify the max
>payload size from BIOS, can I modify it from driver side?

If you want to change value for 82571 device you can do it from eeprom but for other upstream devices I am not sure. I will check with my team.

-Tushar

^ permalink raw reply

* RE: 82571EB: Detected Hardware Unit Hang
From: Dave, Tushar N @ 2012-11-14  3:43 UTC (permalink / raw)
  To: Li Yu
  Cc: Joe Jin, e1000-devel@lists.sf.net, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Mary Mcgrath
In-Reply-To: <50A311E9.9030702@gmail.com>

>-----Original Message-----
>From: Li Yu [mailto:raise.sail@gmail.com]
>Sent: Tuesday, November 13, 2012 7:37 PM
>To: Dave, Tushar N
>Cc: Joe Jin; e1000-devel@lists.sf.net; netdev@vger.kernel.org; linux-
>kernel@vger.kernel.org; Mary Mcgrath
>Subject: Re: 82571EB: Detected Hardware Unit Hang
>
>于 2012年11月09日 04:35, Dave, Tushar N 写道:
>>> -----Original Message-----
>>> From: netdev-owner@vger.kernel.org
>>> [mailto:netdev-owner@vger.kernel.org]
>>> On Behalf Of Joe Jin
>>> Sent: Wednesday, November 07, 2012 10:25 PM
>>> To: e1000-devel@lists.sf.net
>>> Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Mary
>>> Mcgrath
>>> Subject: 82571EB: Detected Hardware Unit Hang
>>>
>>> Hi list,
>>>
>>> IHAC reported "82571EB Detected Hardware Unit Hang" on HP ProLiant
>>> DL360 G6, and have to reboot the server to recover:
>>>
>>> e1000e 0000:06:00.1: eth3: Detected Hardware Unit Hang:
>>>   TDH                  <1a>
>>>   TDT                  <1a>
>>>   next_to_use          <1a>
>>>   next_to_clean        <18>
>>> buffer_info[next_to_clean]:
>>>   time_stamp           <10047a74e>
>>>   next_to_watch        <18>
>>>   jiffies              <10047a88c>
>>>   next_to_watch.status <1>
>>> MAC Status             <80383>
>>> PHY Status             <792d>
>>> PHY 1000BASE-T Status  <3800>
>>> PHY Extended Status    <3000>
>>> PCI Status             <10>
>>>
>>> With newer kernel 2.0.0.1 the issue still reproducible.
>>>
>>> Device info:
>>> 06:00.1 Ethernet controller: Intel Corporation 82571EB Gigabit
>>> Ethernet Controller (Copper) (rev 06)
>>> 06:00.1 0200: 8086:10bc (rev 06)
>>>
>>> I compared lspci output before and after the issue, different as below:
>>> 06:00.1 Ethernet controller: Intel Corporation 82571EB Gigabit
>>> Ethernet Controller (Copper) (rev 06)
>>> 	Subsystem: Hewlett-Packard Company NC364T PCI Express Quad Port
>>> Gigabit Server Adapter
>>> 	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+
>>> Stepping- SERR- FastB2B- DisINTx-
>>> -	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
>>> <TAbort- <MAbort- >SERR- <PERR- INTx-
>>> +	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
>>> +<TAbort- <MAbort- >SERR- <PERR- INTx+
>>
>> Are you sure this is not similar issue as before that you reported.
>> i.e.
>> On Mon, 2012-07-09 at 16:51 +0800, Joe Jin wrote:
>>> I'm seeing a Unit Hang even with the latest e1000e driver 2.0.0 when
>>> doing scp test. this issue is easy do reproduced on SUN FIRE X2270
>>> M2, just copy a big file (>500M) from another server will hit it at
>once.
>>
>> All devices in path from root complex to 82571, should have *same* max
>payload size otherwise it can cause hang.
>> Can you double check this?
>>
>
>We also found such hang problem on 82599EB (ixgbe driver) in RHEL6.3
>kernel, we ever tried to upgrade to latest version (3.8.21 or 3.10.17),
>but it still happens.
>
>Is it probably also due to wrong "max payload size" set in BIOS?
>
It could be or could not be. I would suggest please create another thread with that issue as these two devices are significantly different.

-Tushar

^ permalink raw reply

* Re: 82571EB: Detected Hardware Unit Hang
From: Li Yu @ 2012-11-14  3:37 UTC (permalink / raw)
  To: Dave, Tushar N
  Cc: Joe Jin, e1000-devel@lists.sf.net, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Mary Mcgrath
In-Reply-To: <061C8A8601E8EE4CA8D8FD6990CEA89133487884@ORSMSX102.amr.corp.intel.com>

于 2012年11月09日 04:35, Dave, Tushar N 写道:
>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
>> On Behalf Of Joe Jin
>> Sent: Wednesday, November 07, 2012 10:25 PM
>> To: e1000-devel@lists.sf.net
>> Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Mary Mcgrath
>> Subject: 82571EB: Detected Hardware Unit Hang
>>
>> Hi list,
>>
>> IHAC reported "82571EB Detected Hardware Unit Hang" on HP ProLiant DL360
>> G6, and have to reboot the server to recover:
>>
>> e1000e 0000:06:00.1: eth3: Detected Hardware Unit Hang:
>>   TDH                  <1a>
>>   TDT                  <1a>
>>   next_to_use          <1a>
>>   next_to_clean        <18>
>> buffer_info[next_to_clean]:
>>   time_stamp           <10047a74e>
>>   next_to_watch        <18>
>>   jiffies              <10047a88c>
>>   next_to_watch.status <1>
>> MAC Status             <80383>
>> PHY Status             <792d>
>> PHY 1000BASE-T Status  <3800>
>> PHY Extended Status    <3000>
>> PCI Status             <10>
>>
>> With newer kernel 2.0.0.1 the issue still reproducible.
>>
>> Device info:
>> 06:00.1 Ethernet controller: Intel Corporation 82571EB Gigabit Ethernet
>> Controller (Copper) (rev 06)
>> 06:00.1 0200: 8086:10bc (rev 06)
>>
>> I compared lspci output before and after the issue, different as below:
>> 06:00.1 Ethernet controller: Intel Corporation 82571EB Gigabit Ethernet
>> Controller (Copper) (rev 06)
>> 	Subsystem: Hewlett-Packard Company NC364T PCI Express Quad Port
>> Gigabit Server Adapter
>> 	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+
>> Stepping- SERR- FastB2B- DisINTx-
>> -	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
>> <TAbort- <MAbort- >SERR- <PERR- INTx-
>> +	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
>> +<TAbort- <MAbort- >SERR- <PERR- INTx+
>
> Are you sure this is not similar issue as before that you reported.
> i.e.
> On Mon, 2012-07-09 at 16:51 +0800, Joe Jin wrote:
>> I'm seeing a Unit Hang even with the latest e1000e driver 2.0.0 when
>> doing scp test. this issue is easy do reproduced on SUN FIRE X2270 M2,
>> just copy a big file (>500M) from another server will hit it at once.
>
> All devices in path from root complex to 82571, should have *same* max payload size otherwise it can cause hang.
> Can you double check this?
>

We also found such hang problem on 82599EB (ixgbe driver) in RHEL6.3
kernel, we ever tried to upgrade to latest version (3.8.21 or 3.10.17),
but it still happens.

Is it probably also due to wrong "max payload size" set in BIOS?

Thanks

Yu

> -Tushar
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ permalink raw reply

* Re: 82571EB: Detected Hardware Unit Hang
From: Joe Jin @ 2012-11-14  2:47 UTC (permalink / raw)
  To: Dave, Tushar N
  Cc: e1000-devel@lists.sf.net, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Mary Mcgrath
In-Reply-To: <061C8A8601E8EE4CA8D8FD6990CEA89133487884@ORSMSX102.amr.corp.intel.com>

On 11/09/12 04:35, Dave, Tushar N wrote:
> All devices in path from root complex to 82571, should have *same* max payload size otherwise it can cause hang. 
> Can you double check this?

Hi Tushar,

Checked with hardware vendor and they said no way to modify the max payload size 
from BIOS, can I modify it from driver side?

Thanks,
Joe

^ permalink raw reply

* Re: [PATCH net-next] 8021q: validate SAN MAC address
From: Michael Chan @ 2012-11-14  2:41 UTC (permalink / raw)
  To: John Fastabend, eilong, ariele; +Cc: David Miller, netdev
In-Reply-To: <50A2FAB8.8010803@intel.com>

On Tue, 2012-11-13 at 17:58 -0800, John Fastabend wrote: 
> On 11/13/2012 5:50 PM, Michael Chan wrote:
> > On Tue, 2012-11-13 at 20:24 -0500, David Miller wrote:
> >> From: "Michael Chan" <mchan@broadcom.com>
> >> Date: Tue, 13 Nov 2012 15:40:29 -0800
> >>
> >>> I suppose we can just put the SAN MAC into the real netdev->dev_addr so
> >>> that the VLAN will automatically get it.  But this doesn't seem very
> >>> nice as we would be pretending to have a normal MAC address (for
> >>> networking) in this SAN device.  The networking MAC address is in a
> >>> different PCI function.
> >>
> >> I certainly would prefer if you took that approach.  At least in that
> >> way the addressing of the netdev objects would appear more consistent.
> >>
> > Ok.  To be more complete, I think we need to add a flag or something to
> > such a netdev to indicate that it is a SAN device only.  What's your
> > opinion on that?
> 
> Michael, how do you determine a L2 packet is a SAN type? Do you have
> ACLs in the FW/hardware to prevent other types of L2 traffic from being
> sent? I guess I'm asking what makes it a SAN only device.
> 
Adding Eilon and Ariel from the bnx2x team to help answer the question.
I think we use ndo_select_queue() to put all FCoE related packets onto
the proper ring that is programmed with the proper DCB parameters.
Packets to the other rings will be dropped on such a device.

That's why a flag will be useful so that tools will know its limitation.


> 

^ permalink raw reply

* Re: [RFC PATCH 00/13] Always build GSO/GRO functionality into the kernel
From: Eric Dumazet @ 2012-11-14  2:25 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

On Tue, 2012-11-13 at 20:24 -0500, Vlad Yasevich wrote:
> This patch series is a revision suggested by Eric to solve the problem where
> a host without IPv6 support drops GSO frames from the guest.
> 
> The problem is that GSO/GRO support is per protocol, and when said protocol
> is not loaded or is disabled, packets attempting to go through GSO/GRO code paths
> are dropped.  This causes retransmissions and a two orders of magnitude drop in
> performance.
> 
> Prior attempt to solve the problem simply enabled enough GSO/GRO functionality
> for IPv6 protocol when IPv6 was diabled.  This did not solve the problem when
> the protocol was not build in or was blacklisted.
> To solve the problem, it was suggested that we separate GSO/GRO callback
> registration from packet processing registrations.  That way
> GSO/GRO callbacks can be built into the kernel and always be there.
> This patch series attempts to do just that.
> * Patches 1 and 2 split the GSO/GRO handlers from packet_type and convert
>   to the new structure.
> * Patches 3, 4 and 5 do the same thing for net_protocol structure.
> * The rest of the patches try to incrementally move the IPv6 GSO/GRO
>   code out of the module and into the static kernel build.  Some IPv6
>   helper functions also had to move as well.
> 
> I am currently testing the patches, but if folks could look this over
> and send me any comments, I'd appreciate it.

Seems very nice !

I am just wondering if GSO/GRO is fully enabled at every step ?

^ permalink raw reply

* Re: [RFC PATCH 01/13] net:  Add generic packet offload infrastructure.
From: Eric Dumazet @ 2012-11-14  2:24 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, davem
In-Reply-To: <1352856254-29667-2-git-send-email-vyasevic@redhat.com>

On Tue, 2012-11-13 at 20:24 -0500, Vlad Yasevich wrote:
> Create a new data structure to contain the GRO/GSO callbacks and add
> a new registration mechanism.
> 
> Singed-off-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>  include/linux/netdevice.h |   15 ++++++++
>  net/core/dev.c            |   80 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 95 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index f8eda02..d15af51 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1511,6 +1511,18 @@ struct packet_type {
>  	struct list_head	list;
>  };
>  
> +struct packet_offload {
> +	__be16			type;	/* This is really htons(ether_type). */
> +	struct net_device	*dev;	/* NULL is wildcarded here	     */

Shouldnt this dev pointer be removed at some point in the patch serie ?

> +	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
> +						netdev_features_t features);
> +	int			(*gso_send_check)(struct sk_buff *skb);
> +	struct sk_buff		**(*gro_receive)(struct sk_buff **head,
> +					       struct sk_buff *skb);
> +	int			(*gro_complete)(struct sk_buff *skb);
> +	struct list_head	list;
> +};
> +
>  #include <linux/notifier.h>
>  

^ permalink raw reply

* Re: [PATCH net-next] 8021q: validate SAN MAC address
From: David Miller @ 2012-11-14  1:58 UTC (permalink / raw)
  To: mchan; +Cc: netdev
In-Reply-To: <1352857850.6276.71.camel@LTIRV-MCHAN1.corp.ad.broadcom.com>

From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 13 Nov 2012 17:50:50 -0800

> On Tue, 2012-11-13 at 20:24 -0500, David Miller wrote:
>> From: "Michael Chan" <mchan@broadcom.com>
>> Date: Tue, 13 Nov 2012 15:40:29 -0800
>> 
>> > I suppose we can just put the SAN MAC into the real netdev->dev_addr so
>> > that the VLAN will automatically get it.  But this doesn't seem very
>> > nice as we would be pretending to have a normal MAC address (for
>> > networking) in this SAN device.  The networking MAC address is in a
>> > different PCI function.
>> 
>> I certainly would prefer if you took that approach.  At least in that
>> way the addressing of the netdev objects would appear more consistent.
>> 
> Ok.  To be more complete, I think we need to add a flag or something to
> such a netdev to indicate that it is a SAN device only.  What's your
> opinion on that?

Yes, that would describe the limitation you mentioned.  Maybe
add a new netdev->priv_flags for this.

^ permalink raw reply

* Re: [PATCH net-next] 8021q: validate SAN MAC address
From: John Fastabend @ 2012-11-14  1:58 UTC (permalink / raw)
  To: Michael Chan; +Cc: David Miller, netdev
In-Reply-To: <1352857850.6276.71.camel@LTIRV-MCHAN1.corp.ad.broadcom.com>

On 11/13/2012 5:50 PM, Michael Chan wrote:
> On Tue, 2012-11-13 at 20:24 -0500, David Miller wrote:
>> From: "Michael Chan" <mchan@broadcom.com>
>> Date: Tue, 13 Nov 2012 15:40:29 -0800
>>
>>> I suppose we can just put the SAN MAC into the real netdev->dev_addr so
>>> that the VLAN will automatically get it.  But this doesn't seem very
>>> nice as we would be pretending to have a normal MAC address (for
>>> networking) in this SAN device.  The networking MAC address is in a
>>> different PCI function.
>>
>> I certainly would prefer if you took that approach.  At least in that
>> way the addressing of the netdev objects would appear more consistent.
>>
> Ok.  To be more complete, I think we need to add a flag or something to
> such a netdev to indicate that it is a SAN device only.  What's your
> opinion on that?

Michael, how do you determine a L2 packet is a SAN type? Do you have
ACLs in the FW/hardware to prevent other types of L2 traffic from being
sent? I guess I'm asking what makes it a SAN only device.

.John

^ permalink raw reply

* Re: [PATCH net-next] 8021q: validate SAN MAC address
From: Michael Chan @ 2012-11-14  1:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20121113.202408.79469396824848499.davem@davemloft.net>

On Tue, 2012-11-13 at 20:24 -0500, David Miller wrote:
> From: "Michael Chan" <mchan@broadcom.com>
> Date: Tue, 13 Nov 2012 15:40:29 -0800
> 
> > I suppose we can just put the SAN MAC into the real netdev->dev_addr so
> > that the VLAN will automatically get it.  But this doesn't seem very
> > nice as we would be pretending to have a normal MAC address (for
> > networking) in this SAN device.  The networking MAC address is in a
> > different PCI function.
> 
> I certainly would prefer if you took that approach.  At least in that
> way the addressing of the netdev objects would appear more consistent.
> 
Ok.  To be more complete, I think we need to add a flag or something to
such a netdev to indicate that it is a SAN device only.  What's your
opinion on that?

^ permalink raw reply

* Re: [PATCH V3] wanrouter: Remove it and the drivers that depend on it
From: David Miller @ 2012-11-14  1:44 UTC (permalink / raw)
  To: paul.gortmaker; +Cc: joe, netdev
In-Reply-To: <CAP=VYLqiLpVn99bp08gkSQ+jLFiw8T7vsohJ6e+TdzOtyDwKBQ@mail.gmail.com>


Paul, you can't have HTML content to the list and one of your MIME
sections was HTML, so it was rejected by vger's filters.

Please repost with the HTML stuff removed.

Thanks.

^ permalink raw reply

* [RFC PATCH 13/13] ipv6: Pull IPv6 GSO registration out of the module
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Sing GSO support is now separate, pull it out of the module
and make it its own init call.
Remove the cleanup functions as they are no longer called.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/net/protocol.h     |   11 ++++++-----
 net/ipv6/Makefile          |    6 +++---
 net/ipv6/af_inet6.c        |    3 ---
 net/ipv6/exthdrs.c         |   10 +---------
 net/ipv6/exthdrs_offload.c |    7 -------
 net/ipv6/ip6_offload.c     |   17 ++++++++++++-----
 net/ipv6/ip6_offload.h     |    8 --------
 net/ipv6/tcp_ipv6.c        |   10 +---------
 net/ipv6/tcpv6_offload.c   |    5 -----
 net/ipv6/udp.c             |   10 +---------
 net/ipv6/udp_offload.c     |    5 -----
 11 files changed, 24 insertions(+), 68 deletions(-)

diff --git a/include/net/protocol.h b/include/net/protocol.h
index 7019c16..2c90794 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -25,6 +25,7 @@
 #define _PROTOCOL_H
 
 #include <linux/in6.h>
+#include <linux/skbuff.h>
 #if IS_ENABLED(CONFIG_IPV6)
 #include <linux/ipv6.h>
 #endif
@@ -59,8 +60,6 @@ struct inet6_protocol {
 
 #define INET6_PROTO_NOPOLICY	0x1
 #define INET6_PROTO_FINAL	0x2
-/* This should be set for any extension header which is compatible with GSO. */
-#define INET6_PROTO_GSO_EXTHDR	0x4
 #endif
 
 struct net_offload {
@@ -72,6 +71,8 @@ struct net_offload {
 	int			(*gro_complete)(struct sk_buff *skb);
 	unsigned int		flags;	/* Flags used by IPv6 for now */
 };
+/* This should be set for any extension header which is compatible with GSO. */
+#define INET6_PROTO_GSO_EXTHDR	0x1
 
 /* This is used to register socket interfaces for IP protocols.  */
 struct inet_protosw {
@@ -93,10 +94,10 @@ struct inet_protosw {
 
 extern const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS];
 extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS];
+extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS];
 
 #if IS_ENABLED(CONFIG_IPV6)
 extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS];
-extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS];
 #endif
 
 extern int	inet_add_protocol(const struct net_protocol *prot, unsigned char num);
@@ -109,10 +110,10 @@ extern void	inet_unregister_protosw(struct inet_protosw *p);
 #if IS_ENABLED(CONFIG_IPV6)
 extern int	inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num);
 extern int	inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num);
-extern int	inet6_add_offload(const struct net_offload *prot, unsigned char num);
-extern int	inet6_del_offload(const struct net_offload *prot, unsigned char num);
 extern int	inet6_register_protosw(struct inet_protosw *p);
 extern void	inet6_unregister_protosw(struct inet_protosw *p);
 #endif
+extern int	inet6_add_offload(const struct net_offload *prot, unsigned char num);
+extern int	inet6_del_offload(const struct net_offload *prot, unsigned char num);
 
 #endif	/* _PROTOCOL_H */
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index cdca302..04a475d 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_IPV6) += ipv6.o
 ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		addrlabel.o \
 		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
-		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
+		raw.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
 ipv6-offload :=	ip6_offload.o tcpv6_offload.o udp_offload.o exthdrs_offload.o
@@ -23,7 +23,6 @@ ipv6-$(CONFIG_PROC_FS) += proc.o
 ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
 
 ipv6-objs += $(ipv6-y)
-ipv6-objs += $(ipv6-offload)
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
@@ -41,6 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
-obj-y += addrconf_core.o exthdrs_core.o output_core.o
+obj-y += addrconf_core.o exthdrs_core.o output_core.o protocol.o
+obj-y += $(ipv6-offload)
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index c84d5ba..7bafc51 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -62,7 +62,6 @@
 
 #include <asm/uaccess.h>
 #include <linux/mroute6.h>
-#include "ip6_offload.h"
 
 MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
@@ -707,14 +706,12 @@ static struct packet_type ipv6_packet_type __read_mostly = {
 
 static int __init ipv6_packet_init(void)
 {
-	ipv6_offload_init();
 	dev_add_pack(&ipv6_packet_type);
 	return 0;
 }
 
 static void ipv6_packet_cleanup(void)
 {
-	ipv6_offload_cleanup();
 	dev_remove_pack(&ipv6_packet_type);
 }
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index dc0faab..53f14df 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -48,7 +48,6 @@
 #endif
 
 #include <asm/uaccess.h>
-#include "ip6_offload.h"
 
 int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
 {
@@ -546,13 +545,9 @@ int __init ipv6_exthdrs_init(void)
 {
 	int ret;
 
-	ret = ipv6_exthdrs_offload_init();
-	if (ret)
-		goto out;
-
 	ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
 	if (ret)
-		goto out_offload;
+		goto out;
 
 	ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
 	if (ret)
@@ -568,14 +563,11 @@ out_destopt:
 	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
 out_rthdr:
 	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
-out_offload:
-	ipv6_exthdrs_offload_exit();
 	goto out;
 };
 
 void ipv6_exthdrs_exit(void)
 {
-	ipv6_exthdrs_offload_exit();
 	inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
 	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
 	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c
index 913b9fc..cf77f3a 100644
--- a/net/ipv6/exthdrs_offload.c
+++ b/net/ipv6/exthdrs_offload.c
@@ -39,10 +39,3 @@ out_rt:
 	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
 	goto out;
 }
-
-void ipv6_exthdrs_offload_exit(void)
-{
-	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
-	inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
-}
-
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 01cf983..63d79d9 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -12,6 +12,7 @@
 #include <linux/socket.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/printk.h>
 
 #include <net/protocol.h>
 #include <net/ipv6.h>
@@ -262,12 +263,18 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
 	.gro_complete = ipv6_gro_complete,
 };
 
-void __init ipv6_offload_init(void)
+static int __init ipv6_offload_init(void)
 {
+
+	if (tcpv6_offload_init() < 0)
+		pr_crit("%s: Cannot add TCP protocol offload\n", __func__);
+	if (udp_offload_init() < 0)
+		pr_crit("%s: Cannot add UDP protocol offload\n", __func__);
+	if (ipv6_exthdrs_offload_init() < 0)
+		pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__);
+
 	dev_add_offload(&ipv6_packet_offload);
+	return 0;
 }
 
-void ipv6_offload_cleanup(void)
-{
-	dev_remove_offload(&ipv6_packet_offload);
-}
+fs_initcall(ipv6_offload_init);
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h
index 4e88ddb..2e155c6 100644
--- a/net/ipv6/ip6_offload.h
+++ b/net/ipv6/ip6_offload.h
@@ -12,15 +12,7 @@
 #define __ip6_offload_h
 
 int ipv6_exthdrs_offload_init(void);
-void ipv6_exthdrs_offload_exit(void);
-
 int udp_offload_init(void);
-void udp_offload_cleanup(void);
-
 int tcpv6_offload_init(void);
-void tcpv6_offload_cleanup(void);
-
-extern void ipv6_offload_init(void);
-extern void ipv6_offload_cleanup(void);
 
 #endif
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 58fabc5..c5d2d61 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -71,7 +71,6 @@
 
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
-#include "ip6_offload.h"
 
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
 static void	tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
@@ -2004,13 +2003,9 @@ int __init tcpv6_init(void)
 {
 	int ret;
 
-	ret = tcpv6_offload_init();
-	if (ret)
-		goto out;
-
 	ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
 	if (ret)
-		goto out_offload;
+		goto out;
 
 	/* register inet6 protocol */
 	ret = inet6_register_protosw(&tcpv6_protosw);
@@ -2027,8 +2022,6 @@ out_tcpv6_protosw:
 	inet6_unregister_protosw(&tcpv6_protosw);
 out_tcpv6_protocol:
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
-out_offload:
-	tcpv6_offload_cleanup();
 	goto out;
 }
 
@@ -2037,5 +2030,4 @@ void tcpv6_exit(void)
 	unregister_pernet_subsys(&tcpv6_net_ops);
 	inet6_unregister_protosw(&tcpv6_protosw);
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
-	tcpv6_offload_cleanup();
 }
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index edeafed..3a27fe6 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -91,8 +91,3 @@ int __init tcpv6_offload_init(void)
 {
 	return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
 }
-
-void tcpv6_offload_cleanup(void)
-{
-	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
-}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 013fef7..dfaa29b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -50,7 +50,6 @@
 #include <linux/seq_file.h>
 #include <trace/events/skb.h>
 #include "udp_impl.h"
-#include "ip6_offload.h"
 
 int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 {
@@ -1472,13 +1471,9 @@ int __init udpv6_init(void)
 {
 	int ret;
 
-	ret = udp_offload_init();
-	if (ret)
-		goto out;
-
 	ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
 	if (ret)
-		goto out_offload;
+		goto out;
 
 	ret = inet6_register_protosw(&udpv6_protosw);
 	if (ret)
@@ -1488,8 +1483,6 @@ out:
 
 out_udpv6_protocol:
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
-out_offload:
-	udp_offload_cleanup();
 	goto out;
 }
 
@@ -1497,5 +1490,4 @@ void udpv6_exit(void)
 {
 	inet6_unregister_protosw(&udpv6_protosw);
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
-	udp_offload_cleanup();
 }
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index f964d2b..979e4ab 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -115,8 +115,3 @@ int __init udp_offload_init(void)
 {
 	return inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
 }
-
-void udp_offload_cleanup(void)
-{
-	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
-}
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 12/13] ipv4: Pull GSO registration out of inet_init()
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Since GSO/GRO support is now separated, make IPv4 GSO a
stand-alone init call and not part of inet_init().

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/ipv4/af_inet.c |   34 ++++++++++++++++++++--------------
 1 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 66f63ce..fd34b8c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1665,11 +1665,6 @@ static int ipv4_proc_init(void);
  *	IP protocol layer initialiser
  */
 
-static struct packet_type ip_packet_type __read_mostly = {
-	.type = cpu_to_be16(ETH_P_IP),
-	.func = ip_rcv,
-};
-
 static struct packet_offload ip_packet_offload __read_mostly = {
 	.type = cpu_to_be16(ETH_P_IP),
 	.gso_send_check = inet_gso_send_check,
@@ -1678,6 +1673,26 @@ static struct packet_offload ip_packet_offload __read_mostly = {
 	.gro_complete = inet_gro_complete,
 };
 
+static void __init ipv4_offload_init(void)
+{
+	/*
+	 * Add offloads
+	 */
+	if (inet_add_offload(&udp_offload, IPPROTO_UDP) < 0)
+		pr_crit("%s: Cannot add UDP protocol offload\n", __func__);
+	if (inet_add_offload(&tcp_offload, IPPROTO_TCP) < 0)
+		pr_crit("%s: Cannot add TCP protocol offlaod\n", __func__);
+
+	dev_add_offload(&ip_packet_offload);
+}
+
+fs_initcall(ipv4_offload_init);
+
+static struct packet_type ip_packet_type __read_mostly = {
+	.type = cpu_to_be16(ETH_P_IP),
+	.func = ip_rcv,
+};
+
 static int __init inet_init(void)
 {
 	struct sk_buff *dummy_skb;
@@ -1720,14 +1735,6 @@ static int __init inet_init(void)
 	tcp_prot.sysctl_mem = init_net.ipv4.sysctl_tcp_mem;
 
 	/*
-	 * Add offloads
-	 */
-	if (inet_add_offload(&udp_offload, IPPROTO_UDP) < 0)
-		pr_crit("%s: Cannot add UDP protocol offload\n", __func__);
-	if (inet_add_offload(&tcp_offload, IPPROTO_TCP) < 0)
-		pr_crit("%s: Cannot add TCP protocol offlaod\n", __func__);
-
-	/*
 	 *	Add all the base protocols.
 	 */
 
@@ -1799,7 +1806,6 @@ static int __init inet_init(void)
 
 	ipfrag_init();
 
-	dev_add_offload(&ip_packet_offload);
 	dev_add_pack(&ip_packet_type);
 
 	rc = 0;
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 11/13] ipv6: Update ipv6 static library with newly needed functions
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

UDP offload needs some additional functions to be in the static kernel
for it work correclty.  Move those functions into the core.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/ipv6/Makefile      |    2 +-
 net/ipv6/ip6_output.c  |   65 -----------------------------------------
 net/ipv6/output_core.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 66 deletions(-)
 create mode 100644 net/ipv6/output_core.c

diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 7f25077..cdca302 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -41,6 +41,6 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
-obj-y += addrconf_core.o exthdrs_core.o
+obj-y += addrconf_core.o exthdrs_core.o output_core.o
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index aece3e7..45e6558 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -545,71 +545,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
 	skb_copy_secmark(to, from);
 }
 
-int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
-{
-	u16 offset = sizeof(struct ipv6hdr);
-	struct ipv6_opt_hdr *exthdr =
-				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
-	unsigned int packet_len = skb->tail - skb->network_header;
-	int found_rhdr = 0;
-	*nexthdr = &ipv6_hdr(skb)->nexthdr;
-
-	while (offset + 1 <= packet_len) {
-
-		switch (**nexthdr) {
-
-		case NEXTHDR_HOP:
-			break;
-		case NEXTHDR_ROUTING:
-			found_rhdr = 1;
-			break;
-		case NEXTHDR_DEST:
-#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
-				break;
-#endif
-			if (found_rhdr)
-				return offset;
-			break;
-		default :
-			return offset;
-		}
-
-		offset += ipv6_optlen(exthdr);
-		*nexthdr = &exthdr->nexthdr;
-		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
-						 offset);
-	}
-
-	return offset;
-}
-
-void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
-{
-	static atomic_t ipv6_fragmentation_id;
-	int old, new;
-
-	if (rt && !(rt->dst.flags & DST_NOPEER)) {
-		struct inet_peer *peer;
-		struct net *net;
-
-		net = dev_net(rt->dst.dev);
-		peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
-		if (peer) {
-			fhdr->identification = htonl(inet_getid(peer, 0));
-			inet_putpeer(peer);
-			return;
-		}
-	}
-	do {
-		old = atomic_read(&ipv6_fragmentation_id);
-		new = old + 1;
-		if (!new)
-			new = 1;
-	} while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
-	fhdr->identification = htonl(new);
-}
-
 int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
 	struct sk_buff *frag;
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
new file mode 100644
index 0000000..c2e73e6
--- /dev/null
+++ b/net/ipv6/output_core.c
@@ -0,0 +1,76 @@
+/*
+ * IPv6 library code, needed by static components when full IPv6 support is
+ * not configured or static.  These functions are needed by GSO/GRO implementation.
+ */
+#include <linux/export.h>
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+
+void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
+{
+	static atomic_t ipv6_fragmentation_id;
+	int old, new;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	if (rt && !(rt->dst.flags & DST_NOPEER)) {
+		struct inet_peer *peer;
+		struct net *net;
+
+		net = dev_net(rt->dst.dev);
+		peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
+		if (peer) {
+			fhdr->identification = htonl(inet_getid(peer, 0));
+			inet_putpeer(peer);
+			return;
+		}
+	}
+#endif
+	do {
+		old = atomic_read(&ipv6_fragmentation_id);
+		new = old + 1;
+		if (!new)
+			new = 1;
+	} while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
+	fhdr->identification = htonl(new);
+}
+EXPORT_SYMBOL(ipv6_select_ident);
+
+int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
+{
+	u16 offset = sizeof(struct ipv6hdr);
+	struct ipv6_opt_hdr *exthdr =
+				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
+	unsigned int packet_len = skb->tail - skb->network_header;
+	int found_rhdr = 0;
+	*nexthdr = &ipv6_hdr(skb)->nexthdr;
+
+	while (offset + 1 <= packet_len) {
+
+		switch (**nexthdr) {
+
+		case NEXTHDR_HOP:
+			break;
+		case NEXTHDR_ROUTING:
+			found_rhdr = 1;
+			break;
+		case NEXTHDR_DEST:
+#if IS_ENABLED(CONFIG_IPV6_MIP6)
+			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
+				break;
+#endif
+			if (found_rhdr)
+				return offset;
+			break;
+		default :
+			return offset;
+		}
+
+		offset += ipv6_optlen(exthdr);
+		*nexthdr = &exthdr->nexthdr;
+		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
+						 offset);
+	}
+
+	return offset;
+}
+EXPORT_SYMBOL(ip6_find_1stfragopt);
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 10/13] ipv6: Move exthdr offload support into separate file
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Move the exthdr offload functionality into a separeate
file in preparate for moving it out of the module

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/ipv6/Makefile          |    2 +-
 net/ipv6/exthdrs.c         |   40 +++---------------------------------
 net/ipv6/exthdrs_offload.c |   48 ++++++++++++++++++++++++++++++++++++++++++++
 net/ipv6/ip6_offload.h     |    3 ++
 4 files changed, 56 insertions(+), 37 deletions(-)
 create mode 100644 net/ipv6/exthdrs_offload.c

diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 04b5c96..7f25077 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -10,7 +10,7 @@ ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
-ipv6-offload :=	ip6_offload.o tcpv6_offload.o udp_offload.o
+ipv6-offload :=	ip6_offload.o tcpv6_offload.o udp_offload.o exthdrs_offload.o
 
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index d5a807d..dc0faab 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -48,6 +48,7 @@
 #endif
 
 #include <asm/uaccess.h>
+#include "ip6_offload.h"
 
 int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
 {
@@ -528,20 +529,12 @@ unknown_rh:
 
 static const struct inet6_protocol rthdr_protocol = {
 	.handler	=	ipv6_rthdr_rcv,
-	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
-};
-
-static const struct net_offload rthdr_offload = {
-	.flags		=	INET6_PROTO_GSO_EXTHDR,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 static const struct inet6_protocol destopt_protocol = {
 	.handler	=	ipv6_destopt_rcv,
-	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
-};
-
-static const struct net_offload dstopt_offload = {
-	.flags		=	INET6_PROTO_GSO_EXTHDR,
+	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
 static const struct inet6_protocol nodata_protocol = {
@@ -549,32 +542,6 @@ static const struct inet6_protocol nodata_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
-static int ipv6_exthdrs_offload_init(void)
-{
-	int ret;
-
-	ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
-	if (!ret)
-		goto out;
-
-	ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
-	if (!ret)
-		goto out_rt;
-
-out:
-	return ret;
-
-out_rt:
-	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
-	goto out;
-}
-
-static void ipv6_exthdrs_offload_exit(void)
-{
-	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
-	inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
-}
-
 int __init ipv6_exthdrs_init(void)
 {
 	int ret;
@@ -608,6 +575,7 @@ out_offload:
 
 void ipv6_exthdrs_exit(void)
 {
+	ipv6_exthdrs_offload_exit();
 	inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
 	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
 	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c
new file mode 100644
index 0000000..913b9fc
--- /dev/null
+++ b/net/ipv6/exthdrs_offload.c
@@ -0,0 +1,48 @@
+/*
+ *	IPV6 GSO/GRO offload support
+ *	Linux INET6 implementation
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      IPV6 Extension Header GSO/GRO support
+ */
+#include <net/protocol.h>
+#include "ip6_offload.h"
+
+static const struct net_offload rthdr_offload = {
+	.flags		=	INET6_PROTO_GSO_EXTHDR,
+};
+
+static const struct net_offload dstopt_offload = {
+	.flags		=	INET6_PROTO_GSO_EXTHDR,
+};
+
+int __init ipv6_exthdrs_offload_init(void)
+{
+	int ret;
+
+	ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
+	if (!ret)
+		goto out;
+
+	ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
+	if (!ret)
+		goto out_rt;
+
+out:
+	return ret;
+
+out_rt:
+	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+	goto out;
+}
+
+void ipv6_exthdrs_offload_exit(void)
+{
+	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+	inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
+}
+
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h
index dff7936..4e88ddb 100644
--- a/net/ipv6/ip6_offload.h
+++ b/net/ipv6/ip6_offload.h
@@ -11,6 +11,9 @@
 #ifndef __ip6_offload_h
 #define __ip6_offload_h
 
+int ipv6_exthdrs_offload_init(void);
+void ipv6_exthdrs_offload_exit(void);
+
 int udp_offload_init(void);
 void udp_offload_cleanup(void);
 
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 09/13] ipv6: Separate out UDP offload functionality
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Pull UDP GSO code into a separate file in preparation for moving
the code out of the module.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/ipv6/Makefile      |    2 +-
 net/ipv6/ip6_offload.h |    3 +
 net/ipv6/udp.c         |  104 ++---------------------------------------
 net/ipv6/udp_offload.c |  122 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 130 insertions(+), 101 deletions(-)
 create mode 100644 net/ipv6/udp_offload.c

diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index f47ad9f..04b5c96 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -10,7 +10,7 @@ ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
-ipv6-offload :=	ip6_offload.o tcpv6_offload.o
+ipv6-offload :=	ip6_offload.o tcpv6_offload.o udp_offload.o
 
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h
index 1891946..dff7936 100644
--- a/net/ipv6/ip6_offload.h
+++ b/net/ipv6/ip6_offload.h
@@ -11,6 +11,9 @@
 #ifndef __ip6_offload_h
 #define __ip6_offload_h
 
+int udp_offload_init(void);
+void udp_offload_cleanup(void);
+
 int tcpv6_offload_init(void);
 void tcpv6_offload_cleanup(void);
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index e4cc1f4..013fef7 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -50,6 +50,7 @@
 #include <linux/seq_file.h>
 #include <trace/events/skb.h>
 #include "udp_impl.h"
+#include "ip6_offload.h"
 
 int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 {
@@ -1343,109 +1344,12 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
 }
 #endif
 
-static int udp6_ufo_send_check(struct sk_buff *skb)
-{
-	const struct ipv6hdr *ipv6h;
-	struct udphdr *uh;
-
-	if (!pskb_may_pull(skb, sizeof(*uh)))
-		return -EINVAL;
-
-	ipv6h = ipv6_hdr(skb);
-	uh = udp_hdr(skb);
-
-	uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
-				     IPPROTO_UDP, 0);
-	skb->csum_start = skb_transport_header(skb) - skb->head;
-	skb->csum_offset = offsetof(struct udphdr, check);
-	skb->ip_summed = CHECKSUM_PARTIAL;
-	return 0;
-}
-
-static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
-	netdev_features_t features)
-{
-	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	unsigned int mss;
-	unsigned int unfrag_ip6hlen, unfrag_len;
-	struct frag_hdr *fptr;
-	u8 *mac_start, *prevhdr;
-	u8 nexthdr;
-	u8 frag_hdr_sz = sizeof(struct frag_hdr);
-	int offset;
-	__wsum csum;
-
-	mss = skb_shinfo(skb)->gso_size;
-	if (unlikely(skb->len <= mss))
-		goto out;
-
-	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
-		/* Packet is from an untrusted source, reset gso_segs. */
-		int type = skb_shinfo(skb)->gso_type;
-
-		if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
-			     !(type & (SKB_GSO_UDP))))
-			goto out;
-
-		skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
-
-		segs = NULL;
-		goto out;
-	}
-
-	/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
-	 * do checksum of UDP packets sent as multiple IP fragments.
-	 */
-	offset = skb_checksum_start_offset(skb);
-	csum = skb_checksum(skb, offset, skb->len - offset, 0);
-	offset += skb->csum_offset;
-	*(__sum16 *)(skb->data + offset) = csum_fold(csum);
-	skb->ip_summed = CHECKSUM_NONE;
-
-	/* Check if there is enough headroom to insert fragment header. */
-	if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
-	    pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
-		goto out;
-
-	/* Find the unfragmentable header and shift it left by frag_hdr_sz
-	 * bytes to insert fragment header.
-	 */
-	unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
-	nexthdr = *prevhdr;
-	*prevhdr = NEXTHDR_FRAGMENT;
-	unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
-		     unfrag_ip6hlen;
-	mac_start = skb_mac_header(skb);
-	memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
-
-	skb->mac_header -= frag_hdr_sz;
-	skb->network_header -= frag_hdr_sz;
-
-	fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
-	fptr->nexthdr = nexthdr;
-	fptr->reserved = 0;
-	ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
-
-	/* Fragment the skb. ipv6 header and the remaining fields of the
-	 * fragment header are updated in ipv6_gso_segment()
-	 */
-	segs = skb_segment(skb, features);
-
-out:
-	return segs;
-}
-
 static const struct inet6_protocol udpv6_protocol = {
 	.handler	=	udpv6_rcv,
 	.err_handler	=	udpv6_err,
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static const struct net_offload udpv6_offload = {
-	.gso_send_check =	udp6_ufo_send_check,
-	.gso_segment	=	udp6_ufo_fragment,
-};
-
 /* ------------------------------------------------------------------------ */
 #ifdef CONFIG_PROC_FS
 
@@ -1568,7 +1472,7 @@ int __init udpv6_init(void)
 {
 	int ret;
 
-	ret = inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
+	ret = udp_offload_init();
 	if (ret)
 		goto out;
 
@@ -1585,7 +1489,7 @@ out:
 out_udpv6_protocol:
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
 out_offload:
-	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
+	udp_offload_cleanup();
 	goto out;
 }
 
@@ -1593,5 +1497,5 @@ void udpv6_exit(void)
 {
 	inet6_unregister_protosw(&udpv6_protosw);
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
-	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
+	udp_offload_cleanup();
 }
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
new file mode 100644
index 0000000..f964d2b
--- /dev/null
+++ b/net/ipv6/udp_offload.c
@@ -0,0 +1,122 @@
+/*
+ *	IPV6 GSO/GRO offload support
+ *	Linux INET6 implementation
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      UDPv6 GSO support
+ */
+#include <linux/skbuff.h>
+#include <net/protocol.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include "ip6_offload.h"
+
+static int udp6_ufo_send_check(struct sk_buff *skb)
+{
+	const struct ipv6hdr *ipv6h;
+	struct udphdr *uh;
+
+	if (!pskb_may_pull(skb, sizeof(*uh)))
+		return -EINVAL;
+
+	ipv6h = ipv6_hdr(skb);
+	uh = udp_hdr(skb);
+
+	uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+				     IPPROTO_UDP, 0);
+	skb->csum_start = skb_transport_header(skb) - skb->head;
+	skb->csum_offset = offsetof(struct udphdr, check);
+	skb->ip_summed = CHECKSUM_PARTIAL;
+	return 0;
+}
+
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
+	netdev_features_t features)
+{
+	struct sk_buff *segs = ERR_PTR(-EINVAL);
+	unsigned int mss;
+	unsigned int unfrag_ip6hlen, unfrag_len;
+	struct frag_hdr *fptr;
+	u8 *mac_start, *prevhdr;
+	u8 nexthdr;
+	u8 frag_hdr_sz = sizeof(struct frag_hdr);
+	int offset;
+	__wsum csum;
+
+	mss = skb_shinfo(skb)->gso_size;
+	if (unlikely(skb->len <= mss))
+		goto out;
+
+	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
+		/* Packet is from an untrusted source, reset gso_segs. */
+		int type = skb_shinfo(skb)->gso_type;
+
+		if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY) ||
+			     !(type & (SKB_GSO_UDP))))
+			goto out;
+
+		skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
+
+		segs = NULL;
+		goto out;
+	}
+
+	/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+	 * do checksum of UDP packets sent as multiple IP fragments.
+	 */
+	offset = skb_checksum_start_offset(skb);
+	csum = skb_checksum(skb, offset, skb->len - offset, 0);
+	offset += skb->csum_offset;
+	*(__sum16 *)(skb->data + offset) = csum_fold(csum);
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Check if there is enough headroom to insert fragment header. */
+	if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) &&
+	    pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC))
+		goto out;
+
+	/* Find the unfragmentable header and shift it left by frag_hdr_sz
+	 * bytes to insert fragment header.
+	 */
+	unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+	nexthdr = *prevhdr;
+	*prevhdr = NEXTHDR_FRAGMENT;
+	unfrag_len = skb_network_header(skb) - skb_mac_header(skb) +
+		     unfrag_ip6hlen;
+	mac_start = skb_mac_header(skb);
+	memmove(mac_start-frag_hdr_sz, mac_start, unfrag_len);
+
+	skb->mac_header -= frag_hdr_sz;
+	skb->network_header -= frag_hdr_sz;
+
+	fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
+	fptr->nexthdr = nexthdr;
+	fptr->reserved = 0;
+	ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+
+	/* Fragment the skb. ipv6 header and the remaining fields of the
+	 * fragment header are updated in ipv6_gso_segment()
+	 */
+	segs = skb_segment(skb, features);
+
+out:
+	return segs;
+}
+static const struct net_offload udpv6_offload = {
+	.gso_send_check =	udp6_ufo_send_check,
+	.gso_segment	=	udp6_ufo_fragment,
+};
+
+int __init udp_offload_init(void)
+{
+	return inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
+}
+
+void udp_offload_cleanup(void)
+{
+	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
+}
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 08/13] ipv6: Separate tcp offload functionality
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Pull TCPv6 offload functionality into its won file in preparation
for moving it out of the module.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/net/ip6_checksum.h |   33 +++++++++++++
 net/ipv6/Makefile          |    2 +-
 net/ipv6/ip6_offload.h     |    3 +
 net/ipv6/tcp_ipv6.c        |  113 ++------------------------------------------
 net/ipv6/tcpv6_offload.c   |   98 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 139 insertions(+), 110 deletions(-)
 create mode 100644 net/ipv6/tcpv6_offload.c

diff --git a/include/net/ip6_checksum.h b/include/net/ip6_checksum.h
index bc1b0fd..2f95621 100644
--- a/include/net/ip6_checksum.h
+++ b/include/net/ip6_checksum.h
@@ -91,4 +91,37 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 }
 
 #endif
+
+static __inline__ __sum16 tcp_v6_check(int len,
+				   const struct in6_addr *saddr,
+				   const struct in6_addr *daddr,
+				   __wsum base)
+{
+	return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
+}
+
+static inline void __tcp_v6_send_check(struct sk_buff *skb,
+				       const struct in6_addr *saddr,
+				       const struct in6_addr *daddr)
+{
+	struct tcphdr *th = tcp_hdr(skb);
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
+		skb->csum_start = skb_transport_header(skb) - skb->head;
+		skb->csum_offset = offsetof(struct tcphdr, check);
+	} else {
+		th->check = tcp_v6_check(skb->len, saddr, daddr,
+					 csum_partial(th, th->doff << 2,
+						      skb->csum));
+	}
+}
+
+static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+
+	__tcp_v6_send_check(skb, &np->saddr, &np->daddr);
+}
+
 #endif
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 45bd9cd..f47ad9f 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -10,7 +10,7 @@ ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
-ipv6-offload :=	ip6_offload.o
+ipv6-offload :=	ip6_offload.o tcpv6_offload.o
 
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h
index c09614e..1891946 100644
--- a/net/ipv6/ip6_offload.h
+++ b/net/ipv6/ip6_offload.h
@@ -11,6 +11,9 @@
 #ifndef __ip6_offload_h
 #define __ip6_offload_h
 
+int tcpv6_offload_init(void);
+void tcpv6_offload_cleanup(void);
+
 extern void ipv6_offload_init(void);
 extern void ipv6_offload_cleanup(void);
 
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ac59c84..58fabc5 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -71,15 +71,13 @@
 
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
+#include "ip6_offload.h"
 
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
 static void	tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 				      struct request_sock *req);
 
 static int	tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
-static void	__tcp_v6_send_check(struct sk_buff *skb,
-				    const struct in6_addr *saddr,
-				    const struct in6_addr *daddr);
 
 static const struct inet_connection_sock_af_ops ipv6_mapped;
 static const struct inet_connection_sock_af_ops ipv6_specific;
@@ -119,14 +117,6 @@ static void tcp_v6_hash(struct sock *sk)
 	}
 }
 
-static __inline__ __sum16 tcp_v6_check(int len,
-				   const struct in6_addr *saddr,
-				   const struct in6_addr *daddr,
-				   __wsum base)
-{
-	return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
-}
-
 static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
 {
 	return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
@@ -719,94 +709,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
 };
 #endif
 
-static void __tcp_v6_send_check(struct sk_buff *skb,
-				const struct in6_addr *saddr, const struct in6_addr *daddr)
-{
-	struct tcphdr *th = tcp_hdr(skb);
-
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
-		skb->csum_start = skb_transport_header(skb) - skb->head;
-		skb->csum_offset = offsetof(struct tcphdr, check);
-	} else {
-		th->check = tcp_v6_check(skb->len, saddr, daddr,
-					 csum_partial(th, th->doff << 2,
-						      skb->csum));
-	}
-}
-
-static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
-{
-	struct ipv6_pinfo *np = inet6_sk(sk);
-
-	__tcp_v6_send_check(skb, &np->saddr, &np->daddr);
-}
-
-static int tcp_v6_gso_send_check(struct sk_buff *skb)
-{
-	const struct ipv6hdr *ipv6h;
-	struct tcphdr *th;
-
-	if (!pskb_may_pull(skb, sizeof(*th)))
-		return -EINVAL;
-
-	ipv6h = ipv6_hdr(skb);
-	th = tcp_hdr(skb);
-
-	th->check = 0;
-	skb->ip_summed = CHECKSUM_PARTIAL;
-	__tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
-	return 0;
-}
-
-static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
-					 struct sk_buff *skb)
-{
-	const struct ipv6hdr *iph = skb_gro_network_header(skb);
-	__wsum wsum;
-	__sum16 sum;
-
-	switch (skb->ip_summed) {
-	case CHECKSUM_COMPLETE:
-		if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-				  skb->csum)) {
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-			break;
-		}
-flush:
-		NAPI_GRO_CB(skb)->flush = 1;
-		return NULL;
-
-	case CHECKSUM_NONE:
-		wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
-						    skb_gro_len(skb),
-						    IPPROTO_TCP, 0));
-		sum = csum_fold(skb_checksum(skb,
-					     skb_gro_offset(skb),
-					     skb_gro_len(skb),
-					     wsum));
-		if (sum)
-			goto flush;
-
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		break;
-	}
-
-	return tcp_gro_receive(head, skb);
-}
-
-static int tcp6_gro_complete(struct sk_buff *skb)
-{
-	const struct ipv6hdr *iph = ipv6_hdr(skb);
-	struct tcphdr *th = tcp_hdr(skb);
-
-	th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
-				  &iph->saddr, &iph->daddr, 0);
-	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
-
-	return tcp_gro_complete(skb);
-}
-
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
 				 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
 {
@@ -2066,13 +1968,6 @@ static const struct inet6_protocol tcpv6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static const struct net_offload tcpv6_offload = {
-	.gso_send_check	=	tcp_v6_gso_send_check,
-	.gso_segment	=	tcp_tso_segment,
-	.gro_receive	=	tcp6_gro_receive,
-	.gro_complete	=	tcp6_gro_complete,
-};
-
 static struct inet_protosw tcpv6_protosw = {
 	.type		=	SOCK_STREAM,
 	.protocol	=	IPPROTO_TCP,
@@ -2109,7 +2004,7 @@ int __init tcpv6_init(void)
 {
 	int ret;
 
-	ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
+	ret = tcpv6_offload_init();
 	if (ret)
 		goto out;
 
@@ -2133,7 +2028,7 @@ out_tcpv6_protosw:
 out_tcpv6_protocol:
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
 out_offload:
-	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+	tcpv6_offload_cleanup();
 	goto out;
 }
 
@@ -2142,5 +2037,5 @@ void tcpv6_exit(void)
 	unregister_pernet_subsys(&tcpv6_net_ops);
 	inet6_unregister_protosw(&tcpv6_protosw);
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
-	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+	tcpv6_offload_cleanup();
 }
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
new file mode 100644
index 0000000..edeafed
--- /dev/null
+++ b/net/ipv6/tcpv6_offload.c
@@ -0,0 +1,98 @@
+/*
+ *	IPV6 GSO/GRO offload support
+ *	Linux INET6 implementation
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      TCPv6 GSO/GRO support
+ */
+#include <linux/skbuff.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip6_checksum.h>
+#include "ip6_offload.h"
+
+static int tcp_v6_gso_send_check(struct sk_buff *skb)
+{
+	const struct ipv6hdr *ipv6h;
+	struct tcphdr *th;
+
+	if (!pskb_may_pull(skb, sizeof(*th)))
+		return -EINVAL;
+
+	ipv6h = ipv6_hdr(skb);
+	th = tcp_hdr(skb);
+
+	th->check = 0;
+	skb->ip_summed = CHECKSUM_PARTIAL;
+	__tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
+	return 0;
+}
+
+static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb)
+{
+	const struct ipv6hdr *iph = skb_gro_network_header(skb);
+	__wsum wsum;
+	__sum16 sum;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_COMPLETE:
+		if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
+				  skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			break;
+		}
+flush:
+		NAPI_GRO_CB(skb)->flush = 1;
+		return NULL;
+
+	case CHECKSUM_NONE:
+		wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
+						    skb_gro_len(skb),
+						    IPPROTO_TCP, 0));
+		sum = csum_fold(skb_checksum(skb,
+					     skb_gro_offset(skb),
+					     skb_gro_len(skb),
+					     wsum));
+		if (sum)
+			goto flush;
+
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		break;
+	}
+
+	return tcp_gro_receive(head, skb);
+}
+
+static int tcp6_gro_complete(struct sk_buff *skb)
+{
+	const struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+	th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+				  &iph->saddr, &iph->daddr, 0);
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+
+	return tcp_gro_complete(skb);
+}
+
+static const struct net_offload tcpv6_offload = {
+	.gso_send_check	=	tcp_v6_gso_send_check,
+	.gso_segment	=	tcp_tso_segment,
+	.gro_receive	=	tcp6_gro_receive,
+	.gro_complete	=	tcp6_gro_complete,
+};
+
+int __init tcpv6_offload_init(void)
+{
+	return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
+}
+
+void tcpv6_offload_cleanup(void)
+{
+	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+}
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 07/13] ipv6: Separate ipv6 offload support
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Separate IPv6 offload functionality into its own file
in preparation for the move out of the module

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 net/ipv6/Makefile      |    3 +
 net/ipv6/af_inet6.c    |  249 +-------------------------------------------
 net/ipv6/ip6_offload.c |  273 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv6/ip6_offload.h |   17 +++
 4 files changed, 296 insertions(+), 246 deletions(-)
 create mode 100644 net/ipv6/ip6_offload.c
 create mode 100644 net/ipv6/ip6_offload.h

diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index b6d3f79..45bd9cd 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -10,6 +10,8 @@ ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
 		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
+ipv6-offload :=	ip6_offload.o
+
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
 
@@ -21,6 +23,7 @@ ipv6-$(CONFIG_PROC_FS) += proc.o
 ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
 
 ipv6-objs += $(ipv6-y)
+ipv6-objs += $(ipv6-offload)
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index eb63dac..c84d5ba 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -62,6 +62,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/mroute6.h>
+#include "ip6_offload.h"
 
 MODULE_AUTHOR("Cast of dozens");
 MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
@@ -699,266 +700,22 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
-static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
-{
-	const struct net_offload *ops = NULL;
-
-	for (;;) {
-		struct ipv6_opt_hdr *opth;
-		int len;
-
-		if (proto != NEXTHDR_HOP) {
-			ops = rcu_dereference(inet6_offloads[proto]);
-
-			if (unlikely(!ops))
-				break;
-
-			if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
-				break;
-		}
-
-		if (unlikely(!pskb_may_pull(skb, 8)))
-			break;
-
-		opth = (void *)skb->data;
-		len = ipv6_optlen(opth);
-
-		if (unlikely(!pskb_may_pull(skb, len)))
-			break;
-
-		proto = opth->nexthdr;
-		__skb_pull(skb, len);
-	}
-
-	return proto;
-}
-
-static int ipv6_gso_send_check(struct sk_buff *skb)
-{
-	const struct ipv6hdr *ipv6h;
-	const struct net_offload *ops;
-	int err = -EINVAL;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-		goto out;
-
-	ipv6h = ipv6_hdr(skb);
-	__skb_pull(skb, sizeof(*ipv6h));
-	err = -EPROTONOSUPPORT;
-
-	rcu_read_lock();
-	ops = rcu_dereference(inet6_offloads[
-		ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
-
-	if (likely(ops && ops->gso_send_check)) {
-		skb_reset_transport_header(skb);
-		err = ops->gso_send_check(skb);
-	}
-	rcu_read_unlock();
-
-out:
-	return err;
-}
-
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
-	netdev_features_t features)
-{
-	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	struct ipv6hdr *ipv6h;
-	const struct net_offload *ops;
-	int proto;
-	struct frag_hdr *fptr;
-	unsigned int unfrag_ip6hlen;
-	u8 *prevhdr;
-	int offset = 0;
-
-	if (!(features & NETIF_F_V6_CSUM))
-		features &= ~NETIF_F_SG;
-
-	if (unlikely(skb_shinfo(skb)->gso_type &
-		     ~(SKB_GSO_UDP |
-		       SKB_GSO_DODGY |
-		       SKB_GSO_TCP_ECN |
-		       SKB_GSO_TCPV6 |
-		       0)))
-		goto out;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-		goto out;
-
-	ipv6h = ipv6_hdr(skb);
-	__skb_pull(skb, sizeof(*ipv6h));
-	segs = ERR_PTR(-EPROTONOSUPPORT);
-
-	proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
-	rcu_read_lock();
-	ops = rcu_dereference(inet6_offloads[proto]);
-	if (likely(ops && ops->gso_segment)) {
-		skb_reset_transport_header(skb);
-		segs = ops->gso_segment(skb, features);
-	}
-	rcu_read_unlock();
-
-	if (IS_ERR(segs))
-		goto out;
-
-	for (skb = segs; skb; skb = skb->next) {
-		ipv6h = ipv6_hdr(skb);
-		ipv6h->payload_len = htons(skb->len - skb->mac_len -
-					   sizeof(*ipv6h));
-		if (proto == IPPROTO_UDP) {
-			unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
-			fptr = (struct frag_hdr *)(skb_network_header(skb) +
-				unfrag_ip6hlen);
-			fptr->frag_off = htons(offset);
-			if (skb->next != NULL)
-				fptr->frag_off |= htons(IP6_MF);
-			offset += (ntohs(ipv6h->payload_len) -
-				   sizeof(struct frag_hdr));
-		}
-	}
-
-out:
-	return segs;
-}
-
-static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
-					 struct sk_buff *skb)
-{
-	const struct net_offload *ops;
-	struct sk_buff **pp = NULL;
-	struct sk_buff *p;
-	struct ipv6hdr *iph;
-	unsigned int nlen;
-	unsigned int hlen;
-	unsigned int off;
-	int flush = 1;
-	int proto;
-	__wsum csum;
-
-	off = skb_gro_offset(skb);
-	hlen = off + sizeof(*iph);
-	iph = skb_gro_header_fast(skb, off);
-	if (skb_gro_header_hard(skb, hlen)) {
-		iph = skb_gro_header_slow(skb, hlen, off);
-		if (unlikely(!iph))
-			goto out;
-	}
-
-	skb_gro_pull(skb, sizeof(*iph));
-	skb_set_transport_header(skb, skb_gro_offset(skb));
-
-	flush += ntohs(iph->payload_len) != skb_gro_len(skb);
-
-	rcu_read_lock();
-	proto = iph->nexthdr;
-	ops = rcu_dereference(inet6_offloads[proto]);
-	if (!ops || !ops->gro_receive) {
-		__pskb_pull(skb, skb_gro_offset(skb));
-		proto = ipv6_gso_pull_exthdrs(skb, proto);
-		skb_gro_pull(skb, -skb_transport_offset(skb));
-		skb_reset_transport_header(skb);
-		__skb_push(skb, skb_gro_offset(skb));
-
-		ops = rcu_dereference(inet6_offloads[proto]);
-		if (!ops || !ops->gro_receive)
-			goto out_unlock;
-
-		iph = ipv6_hdr(skb);
-	}
-
-	NAPI_GRO_CB(skb)->proto = proto;
-
-	flush--;
-	nlen = skb_network_header_len(skb);
-
-	for (p = *head; p; p = p->next) {
-		const struct ipv6hdr *iph2;
-		__be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */
-
-		if (!NAPI_GRO_CB(p)->same_flow)
-			continue;
-
-		iph2 = ipv6_hdr(p);
-		first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
-
-		/* All fields must match except length and Traffic Class. */
-		if (nlen != skb_network_header_len(p) ||
-		    (first_word & htonl(0xF00FFFFF)) ||
-		    memcmp(&iph->nexthdr, &iph2->nexthdr,
-			   nlen - offsetof(struct ipv6hdr, nexthdr))) {
-			NAPI_GRO_CB(p)->same_flow = 0;
-			continue;
-		}
-		/* flush if Traffic Class fields are different */
-		NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
-		NAPI_GRO_CB(p)->flush |= flush;
-	}
-
-	NAPI_GRO_CB(skb)->flush |= flush;
-
-	csum = skb->csum;
-	skb_postpull_rcsum(skb, iph, skb_network_header_len(skb));
-
-	pp = ops->gro_receive(head, skb);
-
-	skb->csum = csum;
-
-out_unlock:
-	rcu_read_unlock();
-
-out:
-	NAPI_GRO_CB(skb)->flush |= flush;
-
-	return pp;
-}
-
-static int ipv6_gro_complete(struct sk_buff *skb)
-{
-	const struct net_offload *ops;
-	struct ipv6hdr *iph = ipv6_hdr(skb);
-	int err = -ENOSYS;
-
-	iph->payload_len = htons(skb->len - skb_network_offset(skb) -
-				 sizeof(*iph));
-
-	rcu_read_lock();
-	ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]);
-	if (WARN_ON(!ops || !ops->gro_complete))
-		goto out_unlock;
-
-	err = ops->gro_complete(skb);
-
-out_unlock:
-	rcu_read_unlock();
-
-	return err;
-}
-
 static struct packet_type ipv6_packet_type __read_mostly = {
 	.type = cpu_to_be16(ETH_P_IPV6),
 	.func = ipv6_rcv,
 };
 
-static struct packet_offload ipv6_packet_offload __read_mostly = {
-	.type = cpu_to_be16(ETH_P_IPV6),
-	.gso_send_check = ipv6_gso_send_check,
-	.gso_segment = ipv6_gso_segment,
-	.gro_receive = ipv6_gro_receive,
-	.gro_complete = ipv6_gro_complete,
-};
-
 static int __init ipv6_packet_init(void)
 {
-	dev_add_offload(&ipv6_packet_offload);
+	ipv6_offload_init();
 	dev_add_pack(&ipv6_packet_type);
 	return 0;
 }
 
 static void ipv6_packet_cleanup(void)
 {
+	ipv6_offload_cleanup();
 	dev_remove_pack(&ipv6_packet_type);
-	dev_remove_offload(&ipv6_packet_offload);
 }
 
 static int __net_init ipv6_init_mibs(struct net *net)
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
new file mode 100644
index 0000000..01cf983
--- /dev/null
+++ b/net/ipv6/ip6_offload.c
@@ -0,0 +1,273 @@
+/*
+ *	IPV6 GSO/GRO offload support
+ *	Linux INET6 implementation
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include <net/protocol.h>
+#include <net/ipv6.h>
+
+#include "ip6_offload.h"
+
+static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
+{
+	const struct net_offload *ops = NULL;
+
+	for (;;) {
+		struct ipv6_opt_hdr *opth;
+		int len;
+
+		if (proto != NEXTHDR_HOP) {
+			ops = rcu_dereference(inet6_offloads[proto]);
+
+			if (unlikely(!ops))
+				break;
+
+			if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
+				break;
+		}
+
+		if (unlikely(!pskb_may_pull(skb, 8)))
+			break;
+
+		opth = (void *)skb->data;
+		len = ipv6_optlen(opth);
+
+		if (unlikely(!pskb_may_pull(skb, len)))
+			break;
+
+		proto = opth->nexthdr;
+		__skb_pull(skb, len);
+	}
+
+	return proto;
+}
+
+static int ipv6_gso_send_check(struct sk_buff *skb)
+{
+	const struct ipv6hdr *ipv6h;
+	const struct net_offload *ops;
+	int err = -EINVAL;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+		goto out;
+
+	ipv6h = ipv6_hdr(skb);
+	__skb_pull(skb, sizeof(*ipv6h));
+	err = -EPROTONOSUPPORT;
+
+	rcu_read_lock();
+	ops = rcu_dereference(inet6_offloads[
+		ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
+
+	if (likely(ops && ops->gso_send_check)) {
+		skb_reset_transport_header(skb);
+		err = ops->gso_send_check(skb);
+	}
+	rcu_read_unlock();
+
+out:
+	return err;
+}
+
+static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
+	netdev_features_t features)
+{
+	struct sk_buff *segs = ERR_PTR(-EINVAL);
+	struct ipv6hdr *ipv6h;
+	const struct net_offload *ops;
+	int proto;
+	struct frag_hdr *fptr;
+	unsigned int unfrag_ip6hlen;
+	u8 *prevhdr;
+	int offset = 0;
+
+	if (!(features & NETIF_F_V6_CSUM))
+		features &= ~NETIF_F_SG;
+
+	if (unlikely(skb_shinfo(skb)->gso_type &
+		     ~(SKB_GSO_UDP |
+		       SKB_GSO_DODGY |
+		       SKB_GSO_TCP_ECN |
+		       SKB_GSO_TCPV6 |
+		       0)))
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+		goto out;
+
+	ipv6h = ipv6_hdr(skb);
+	__skb_pull(skb, sizeof(*ipv6h));
+	segs = ERR_PTR(-EPROTONOSUPPORT);
+
+	proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+	rcu_read_lock();
+	ops = rcu_dereference(inet6_offloads[proto]);
+	if (likely(ops && ops->gso_segment)) {
+		skb_reset_transport_header(skb);
+		segs = ops->gso_segment(skb, features);
+	}
+	rcu_read_unlock();
+
+	if (IS_ERR(segs))
+		goto out;
+
+	for (skb = segs; skb; skb = skb->next) {
+		ipv6h = ipv6_hdr(skb);
+		ipv6h->payload_len = htons(skb->len - skb->mac_len -
+					   sizeof(*ipv6h));
+		if (proto == IPPROTO_UDP) {
+			unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+			fptr = (struct frag_hdr *)(skb_network_header(skb) +
+				unfrag_ip6hlen);
+			fptr->frag_off = htons(offset);
+			if (skb->next != NULL)
+				fptr->frag_off |= htons(IP6_MF);
+			offset += (ntohs(ipv6h->payload_len) -
+				   sizeof(struct frag_hdr));
+		}
+	}
+
+out:
+	return segs;
+}
+
+static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
+					 struct sk_buff *skb)
+{
+	const struct net_offload *ops;
+	struct sk_buff **pp = NULL;
+	struct sk_buff *p;
+	struct ipv6hdr *iph;
+	unsigned int nlen;
+	unsigned int hlen;
+	unsigned int off;
+	int flush = 1;
+	int proto;
+	__wsum csum;
+
+	off = skb_gro_offset(skb);
+	hlen = off + sizeof(*iph);
+	iph = skb_gro_header_fast(skb, off);
+	if (skb_gro_header_hard(skb, hlen)) {
+		iph = skb_gro_header_slow(skb, hlen, off);
+		if (unlikely(!iph))
+			goto out;
+	}
+
+	skb_gro_pull(skb, sizeof(*iph));
+	skb_set_transport_header(skb, skb_gro_offset(skb));
+
+	flush += ntohs(iph->payload_len) != skb_gro_len(skb);
+
+	rcu_read_lock();
+	proto = iph->nexthdr;
+	ops = rcu_dereference(inet6_offloads[proto]);
+	if (!ops || !ops->gro_receive) {
+		__pskb_pull(skb, skb_gro_offset(skb));
+		proto = ipv6_gso_pull_exthdrs(skb, proto);
+		skb_gro_pull(skb, -skb_transport_offset(skb));
+		skb_reset_transport_header(skb);
+		__skb_push(skb, skb_gro_offset(skb));
+
+		ops = rcu_dereference(inet6_offloads[proto]);
+		if (!ops || !ops->gro_receive)
+			goto out_unlock;
+
+		iph = ipv6_hdr(skb);
+	}
+
+	NAPI_GRO_CB(skb)->proto = proto;
+
+	flush--;
+	nlen = skb_network_header_len(skb);
+
+	for (p = *head; p; p = p->next) {
+		const struct ipv6hdr *iph2;
+		__be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */
+
+		if (!NAPI_GRO_CB(p)->same_flow)
+			continue;
+
+		iph2 = ipv6_hdr(p);
+		first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
+
+		/* All fields must match except length and Traffic Class. */
+		if (nlen != skb_network_header_len(p) ||
+		    (first_word & htonl(0xF00FFFFF)) ||
+		    memcmp(&iph->nexthdr, &iph2->nexthdr,
+			   nlen - offsetof(struct ipv6hdr, nexthdr))) {
+			NAPI_GRO_CB(p)->same_flow = 0;
+			continue;
+		}
+		/* flush if Traffic Class fields are different */
+		NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
+		NAPI_GRO_CB(p)->flush |= flush;
+	}
+
+	NAPI_GRO_CB(skb)->flush |= flush;
+
+	csum = skb->csum;
+	skb_postpull_rcsum(skb, iph, skb_network_header_len(skb));
+
+	pp = ops->gro_receive(head, skb);
+
+	skb->csum = csum;
+
+out_unlock:
+	rcu_read_unlock();
+
+out:
+	NAPI_GRO_CB(skb)->flush |= flush;
+
+	return pp;
+}
+
+static int ipv6_gro_complete(struct sk_buff *skb)
+{
+	const struct net_offload *ops;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	int err = -ENOSYS;
+
+	iph->payload_len = htons(skb->len - skb_network_offset(skb) -
+				 sizeof(*iph));
+
+	rcu_read_lock();
+	ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]);
+	if (WARN_ON(!ops || !ops->gro_complete))
+		goto out_unlock;
+
+	err = ops->gro_complete(skb);
+
+out_unlock:
+	rcu_read_unlock();
+
+	return err;
+}
+
+static struct packet_offload ipv6_packet_offload __read_mostly = {
+	.type = cpu_to_be16(ETH_P_IPV6),
+	.gso_send_check = ipv6_gso_send_check,
+	.gso_segment = ipv6_gso_segment,
+	.gro_receive = ipv6_gro_receive,
+	.gro_complete = ipv6_gro_complete,
+};
+
+void __init ipv6_offload_init(void)
+{
+	dev_add_offload(&ipv6_packet_offload);
+}
+
+void ipv6_offload_cleanup(void)
+{
+	dev_remove_offload(&ipv6_packet_offload);
+}
diff --git a/net/ipv6/ip6_offload.h b/net/ipv6/ip6_offload.h
new file mode 100644
index 0000000..c09614e
--- /dev/null
+++ b/net/ipv6/ip6_offload.h
@@ -0,0 +1,17 @@
+/*
+ *	IPV6 GSO/GRO offload support
+ *	Linux INET6 implementation
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __ip6_offload_h
+#define __ip6_offload_h
+
+extern void ipv6_offload_init(void);
+extern void ipv6_offload_cleanup(void);
+
+#endif
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 06/13] ipv6: Switch to using new offload infrastructure.
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Switch IPv6 protocol to using the new GRO/GSO calls and data.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/net/protocol.h |    8 --------
 net/ipv6/af_inet6.c    |   22 +++++++++++-----------
 net/ipv6/exthdrs.c     |   38 +++++++++++++++++++++++++++++++++++---
 net/ipv6/tcp_ipv6.c    |   17 ++++++++++-------
 net/ipv6/udp.c         |   11 ++++++++---
 5 files changed, 64 insertions(+), 32 deletions(-)

diff --git a/include/net/protocol.h b/include/net/protocol.h
index 3bb7051..7019c16 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -54,14 +54,6 @@ struct inet6_protocol {
 			       struct inet6_skb_parm *opt,
 			       u8 type, u8 code, int offset,
 			       __be32 info);
-
-	int	(*gso_send_check)(struct sk_buff *skb);
-	struct sk_buff *(*gso_segment)(struct sk_buff *skb,
-				       netdev_features_t features);
-	struct sk_buff **(*gro_receive)(struct sk_buff **head,
-					struct sk_buff *skb);
-	int	(*gro_complete)(struct sk_buff *skb);
-
 	unsigned int	flags;	/* INET6_PROTO_xxx */
 };
 
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 6e24517..eb63dac 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -701,14 +701,14 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
 static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
 {
-	const struct inet6_protocol *ops = NULL;
+	const struct net_offload *ops = NULL;
 
 	for (;;) {
 		struct ipv6_opt_hdr *opth;
 		int len;
 
 		if (proto != NEXTHDR_HOP) {
-			ops = rcu_dereference(inet6_protos[proto]);
+			ops = rcu_dereference(inet6_offloads[proto]);
 
 			if (unlikely(!ops))
 				break;
@@ -736,7 +736,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
 static int ipv6_gso_send_check(struct sk_buff *skb)
 {
 	const struct ipv6hdr *ipv6h;
-	const struct inet6_protocol *ops;
+	const struct net_offload *ops;
 	int err = -EINVAL;
 
 	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
@@ -747,7 +747,7 @@ static int ipv6_gso_send_check(struct sk_buff *skb)
 	err = -EPROTONOSUPPORT;
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet6_protos[
+	ops = rcu_dereference(inet6_offloads[
 		ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
 
 	if (likely(ops && ops->gso_send_check)) {
@@ -765,7 +765,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
 {
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
 	struct ipv6hdr *ipv6h;
-	const struct inet6_protocol *ops;
+	const struct net_offload *ops;
 	int proto;
 	struct frag_hdr *fptr;
 	unsigned int unfrag_ip6hlen;
@@ -792,7 +792,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
 
 	proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 	rcu_read_lock();
-	ops = rcu_dereference(inet6_protos[proto]);
+	ops = rcu_dereference(inet6_offloads[proto]);
 	if (likely(ops && ops->gso_segment)) {
 		skb_reset_transport_header(skb);
 		segs = ops->gso_segment(skb, features);
@@ -825,7 +825,7 @@ out:
 static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
 					 struct sk_buff *skb)
 {
-	const struct inet6_protocol *ops;
+	const struct net_offload *ops;
 	struct sk_buff **pp = NULL;
 	struct sk_buff *p;
 	struct ipv6hdr *iph;
@@ -852,7 +852,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
 
 	rcu_read_lock();
 	proto = iph->nexthdr;
-	ops = rcu_dereference(inet6_protos[proto]);
+	ops = rcu_dereference(inet6_offloads[proto]);
 	if (!ops || !ops->gro_receive) {
 		__pskb_pull(skb, skb_gro_offset(skb));
 		proto = ipv6_gso_pull_exthdrs(skb, proto);
@@ -860,7 +860,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
 		skb_reset_transport_header(skb);
 		__skb_push(skb, skb_gro_offset(skb));
 
-		ops = rcu_dereference(inet6_protos[proto]);
+		ops = rcu_dereference(inet6_offloads[proto]);
 		if (!ops || !ops->gro_receive)
 			goto out_unlock;
 
@@ -915,7 +915,7 @@ out:
 
 static int ipv6_gro_complete(struct sk_buff *skb)
 {
-	const struct inet6_protocol *ops;
+	const struct net_offload *ops;
 	struct ipv6hdr *iph = ipv6_hdr(skb);
 	int err = -ENOSYS;
 
@@ -923,7 +923,7 @@ static int ipv6_gro_complete(struct sk_buff *skb)
 				 sizeof(*iph));
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet6_protos[NAPI_GRO_CB(skb)->proto]);
+	ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]);
 	if (WARN_ON(!ops || !ops->gro_complete))
 		goto out_unlock;
 
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8c01574..d5a807d 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -549,14 +549,44 @@ static const struct inet6_protocol nodata_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY,
 };
 
+static int ipv6_exthdrs_offload_init(void)
+{
+	int ret;
+
+	ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
+	if (!ret)
+		goto out;
+
+	ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
+	if (!ret)
+		goto out_rt;
+
+out:
+	return ret;
+
+out_rt:
+	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+	goto out;
+}
+
+static void ipv6_exthdrs_offload_exit(void)
+{
+	inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+	inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
+}
+
 int __init ipv6_exthdrs_init(void)
 {
 	int ret;
 
-	ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+	ret = ipv6_exthdrs_offload_init();
 	if (ret)
 		goto out;
 
+	ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+	if (ret)
+		goto out_offload;
+
 	ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
 	if (ret)
 		goto out_rthdr;
@@ -567,10 +597,12 @@ int __init ipv6_exthdrs_init(void)
 
 out:
 	return ret;
-out_rthdr:
-	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
 out_destopt:
 	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
+out_rthdr:
+	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
+out_offload:
+	ipv6_exthdrs_offload_exit();
 	goto out;
 };
 
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8ce2c30..ac59c84 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2063,10 +2063,6 @@ static const struct inet6_protocol tcpv6_protocol = {
 	.early_demux	=	tcp_v6_early_demux,
 	.handler	=	tcp_v6_rcv,
 	.err_handler	=	tcp_v6_err,
-	.gso_send_check	=	tcp_v6_gso_send_check,
-	.gso_segment	=	tcp_tso_segment,
-	.gro_receive	=	tcp6_gro_receive,
-	.gro_complete	=	tcp6_gro_complete,
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
@@ -2113,10 +2109,14 @@ int __init tcpv6_init(void)
 {
 	int ret;
 
-	ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+	ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
 	if (ret)
 		goto out;
 
+	ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
+	if (ret)
+		goto out_offload;
+
 	/* register inet6 protocol */
 	ret = inet6_register_protosw(&tcpv6_protosw);
 	if (ret)
@@ -2128,10 +2128,12 @@ int __init tcpv6_init(void)
 out:
 	return ret;
 
-out_tcpv6_protocol:
-	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
 out_tcpv6_protosw:
 	inet6_unregister_protosw(&tcpv6_protosw);
+out_tcpv6_protocol:
+	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+out_offload:
+	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
 	goto out;
 }
 
@@ -2140,4 +2142,5 @@ void tcpv6_exit(void)
 	unregister_pernet_subsys(&tcpv6_net_ops);
 	inet6_unregister_protosw(&tcpv6_protosw);
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
+	inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
 }
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3ad44e1..e4cc1f4 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1438,8 +1438,6 @@ out:
 static const struct inet6_protocol udpv6_protocol = {
 	.handler	=	udpv6_rcv,
 	.err_handler	=	udpv6_err,
-	.gso_send_check =	udp6_ufo_send_check,
-	.gso_segment	=	udp6_ufo_fragment,
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
@@ -1570,10 +1568,14 @@ int __init udpv6_init(void)
 {
 	int ret;
 
-	ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
+	ret = inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
 	if (ret)
 		goto out;
 
+	ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
+	if (ret)
+		goto out_offload;
+
 	ret = inet6_register_protosw(&udpv6_protosw);
 	if (ret)
 		goto out_udpv6_protocol;
@@ -1582,6 +1584,8 @@ out:
 
 out_udpv6_protocol:
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
+out_offload:
+	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
 	goto out;
 }
 
@@ -1589,4 +1593,5 @@ void udpv6_exit(void)
 {
 	inet6_unregister_protosw(&udpv6_protosw);
 	inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
+	inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
 }
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 05/13] ipv4: Switch to using the new offload infrastructure.
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Switch IPv4 code base to using the new GRO/GSO calls and data.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/net/protocol.h |    6 ------
 net/ipv4/af_inet.c     |   30 ++++++++++++++++--------------
 2 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/include/net/protocol.h b/include/net/protocol.h
index 637e1bb..3bb7051 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -40,12 +40,6 @@ struct net_protocol {
 	void			(*early_demux)(struct sk_buff *skb);
 	int			(*handler)(struct sk_buff *skb);
 	void			(*err_handler)(struct sk_buff *skb, u32 info);
-	int			(*gso_send_check)(struct sk_buff *skb);
-	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
-					       netdev_features_t features);
-	struct sk_buff	      **(*gro_receive)(struct sk_buff **head,
-					       struct sk_buff *skb);
-	int			(*gro_complete)(struct sk_buff *skb);
 	unsigned int		no_policy:1,
 				netns_ok:1;
 };
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 3918d86..66f63ce 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1251,7 +1251,7 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);
 
 static int inet_gso_send_check(struct sk_buff *skb)
 {
-	const struct net_protocol *ops;
+	const struct net_offload *ops;
 	const struct iphdr *iph;
 	int proto;
 	int ihl;
@@ -1275,7 +1275,7 @@ static int inet_gso_send_check(struct sk_buff *skb)
 	err = -EPROTONOSUPPORT;
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet_protos[proto]);
+	ops = rcu_dereference(inet_offloads[proto]);
 	if (likely(ops && ops->gso_send_check))
 		err = ops->gso_send_check(skb);
 	rcu_read_unlock();
@@ -1288,7 +1288,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 	netdev_features_t features)
 {
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	const struct net_protocol *ops;
+	const struct net_offload *ops;
 	struct iphdr *iph;
 	int proto;
 	int ihl;
@@ -1325,7 +1325,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 	segs = ERR_PTR(-EPROTONOSUPPORT);
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet_protos[proto]);
+	ops = rcu_dereference(inet_offloads[proto]);
 	if (likely(ops && ops->gso_segment))
 		segs = ops->gso_segment(skb, features);
 	rcu_read_unlock();
@@ -1356,7 +1356,7 @@ out:
 static struct sk_buff **inet_gro_receive(struct sk_buff **head,
 					 struct sk_buff *skb)
 {
-	const struct net_protocol *ops;
+	const struct net_offload *ops;
 	struct sk_buff **pp = NULL;
 	struct sk_buff *p;
 	const struct iphdr *iph;
@@ -1378,7 +1378,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
 	proto = iph->protocol;
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet_protos[proto]);
+	ops = rcu_dereference(inet_offloads[proto]);
 	if (!ops || !ops->gro_receive)
 		goto out_unlock;
 
@@ -1435,7 +1435,7 @@ static int inet_gro_complete(struct sk_buff *skb)
 {
 	__be16 newlen = htons(skb->len - skb_network_offset(skb));
 	struct iphdr *iph = ip_hdr(skb);
-	const struct net_protocol *ops;
+	const struct net_offload *ops;
 	int proto = iph->protocol;
 	int err = -ENOSYS;
 
@@ -1443,7 +1443,7 @@ static int inet_gro_complete(struct sk_buff *skb)
 	iph->tot_len = newlen;
 
 	rcu_read_lock();
-	ops = rcu_dereference(inet_protos[proto]);
+	ops = rcu_dereference(inet_offloads[proto]);
 	if (WARN_ON(!ops || !ops->gro_complete))
 		goto out_unlock;
 
@@ -1558,10 +1558,6 @@ static const struct net_protocol tcp_protocol = {
 	.early_demux	=	tcp_v4_early_demux,
 	.handler	=	tcp_v4_rcv,
 	.err_handler	=	tcp_v4_err,
-	.gso_send_check	=	tcp_v4_gso_send_check,
-	.gso_segment	=	tcp_tso_segment,
-	.gro_receive	=	tcp4_gro_receive,
-	.gro_complete	=	tcp4_gro_complete,
 	.no_policy	=	1,
 	.netns_ok	=	1,
 };
@@ -1576,8 +1572,6 @@ static const struct net_offload tcp_offload = {
 static const struct net_protocol udp_protocol = {
 	.handler =	udp_rcv,
 	.err_handler =	udp_err,
-	.gso_send_check = udp4_ufo_send_check,
-	.gso_segment = udp4_ufo_fragment,
 	.no_policy =	1,
 	.netns_ok =	1,
 };
@@ -1726,6 +1720,14 @@ static int __init inet_init(void)
 	tcp_prot.sysctl_mem = init_net.ipv4.sysctl_tcp_mem;
 
 	/*
+	 * Add offloads
+	 */
+	if (inet_add_offload(&udp_offload, IPPROTO_UDP) < 0)
+		pr_crit("%s: Cannot add UDP protocol offload\n", __func__);
+	if (inet_add_offload(&tcp_offload, IPPROTO_TCP) < 0)
+		pr_crit("%s: Cannot add TCP protocol offlaod\n", __func__);
+
+	/*
 	 *	Add all the base protocols.
 	 */
 
-- 
1.7.7.6

^ permalink raw reply related

* [RFC PATCH 04/13] ipv6: Add new offload registration infrastructure.
From: Vlad Yasevich @ 2012-11-14  1:24 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, davem
In-Reply-To: <1352856254-29667-1-git-send-email-vyasevic@redhat.com>

Create a new data structure for IPv6 protocols that holds GRO/GSO
callbacks and a new array to track the protocols that register GRO/GSO.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
---
 include/net/protocol.h |    4 ++++
 net/ipv6/exthdrs.c     |    8 ++++++++
 net/ipv6/protocol.c    |   21 +++++++++++++++++++++
 net/ipv6/tcp_ipv6.c    |    7 +++++++
 net/ipv6/udp.c         |    5 +++++
 5 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/include/net/protocol.h b/include/net/protocol.h
index d8ecb17..637e1bb 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -84,6 +84,7 @@ struct net_offload {
 	struct sk_buff	      **(*gro_receive)(struct sk_buff **head,
 					       struct sk_buff *skb);
 	int			(*gro_complete)(struct sk_buff *skb);
+	unsigned int		flags;	/* Flags used by IPv6 for now */
 };
 
 /* This is used to register socket interfaces for IP protocols.  */
@@ -109,6 +110,7 @@ extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS];
 
 #if IS_ENABLED(CONFIG_IPV6)
 extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS];
+extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS];
 #endif
 
 extern int	inet_add_protocol(const struct net_protocol *prot, unsigned char num);
@@ -121,6 +123,8 @@ extern void	inet_unregister_protosw(struct inet_protosw *p);
 #if IS_ENABLED(CONFIG_IPV6)
 extern int	inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num);
 extern int	inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num);
+extern int	inet6_add_offload(const struct net_offload *prot, unsigned char num);
+extern int	inet6_del_offload(const struct net_offload *prot, unsigned char num);
 extern int	inet6_register_protosw(struct inet_protosw *p);
 extern void	inet6_unregister_protosw(struct inet_protosw *p);
 #endif
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index fa3d9c3..8c01574 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -531,11 +531,19 @@ static const struct inet6_protocol rthdr_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
 };
 
+static const struct net_offload rthdr_offload = {
+	.flags		=	INET6_PROTO_GSO_EXTHDR,
+};
+
 static const struct inet6_protocol destopt_protocol = {
 	.handler	=	ipv6_destopt_rcv,
 	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
 };
 
+static const struct net_offload dstopt_offload = {
+	.flags		=	INET6_PROTO_GSO_EXTHDR,
+};
+
 static const struct inet6_protocol nodata_protocol = {
 	.handler	=	dst_discard,
 	.flags		=	INET6_PROTO_NOPOLICY,
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index 053082d..f7c53a7 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -26,6 +26,7 @@
 #include <net/protocol.h>
 
 const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly;
+const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly;
 
 int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
 {
@@ -34,6 +35,13 @@ int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol
 }
 EXPORT_SYMBOL(inet6_add_protocol);
 
+int inet6_add_offload(const struct net_offload *prot, unsigned char protocol)
+{
+	return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol],
+			NULL, prot) ? 0 : -1;
+}
+EXPORT_SYMBOL(inet6_add_offload);
+
 /*
  *	Remove a protocol from the hash tables.
  */
@@ -50,3 +58,16 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol
 	return ret;
 }
 EXPORT_SYMBOL(inet6_del_protocol);
+
+int inet6_del_offload(const struct net_offload *prot, unsigned char protocol)
+{
+	int ret;
+
+	ret = (cmpxchg((const struct net_offload **)&inet6_offloads[protocol],
+		       prot, NULL) == prot) ? 0 : -1;
+
+	synchronize_net();
+
+	return ret;
+}
+EXPORT_SYMBOL(inet6_del_offload);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 26175bf..8ce2c30 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2070,6 +2070,13 @@ static const struct inet6_protocol tcpv6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
+static const struct net_offload tcpv6_offload = {
+	.gso_send_check	=	tcp_v6_gso_send_check,
+	.gso_segment	=	tcp_tso_segment,
+	.gro_receive	=	tcp6_gro_receive,
+	.gro_complete	=	tcp6_gro_complete,
+};
+
 static struct inet_protosw tcpv6_protosw = {
 	.type		=	SOCK_STREAM,
 	.protocol	=	IPPROTO_TCP,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index fc99972..3ad44e1 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1443,6 +1443,11 @@ static const struct inet6_protocol udpv6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
+static const struct net_offload udpv6_offload = {
+	.gso_send_check =	udp6_ufo_send_check,
+	.gso_segment	=	udp6_ufo_fragment,
+};
+
 /* ------------------------------------------------------------------------ */
 #ifdef CONFIG_PROC_FS
 
-- 
1.7.7.6

^ permalink raw reply related


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