Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next 3/3] net/mlx4_en: Fix handling of dma_map failure
From: Francois Romieu @ 2013-08-19 20:42 UTC (permalink / raw)
  To: Amir Vadai; +Cc: David S. Miller, netdev
In-Reply-To: <1376894542-27854-4-git-send-email-amirv@mellanox.com>

Amir Vadai <amirv@mellanox.com> :
[...]
> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> index 157bcd1..92d7097 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> @@ -673,6 +673,64 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
>  	tx_info->skb = skb;
>  	tx_info->nr_txbb = nr_txbb;
>  
> +	if (lso_header_size)
> +		data = ((void *)&tx_desc->lso + ALIGN(lso_header_size + 4,
> +						      DS_SIZE));
> +	else
> +		data = &tx_desc->data;
> +
> +	/* valid only for none inline segments */
> +	tx_info->data_offset = (void *)data - (void *)tx_desc;
> +
> +	tx_info->linear = (lso_header_size < skb_headlen(skb) &&
> +			   !is_inline(skb, NULL)) ? 1 : 0;
> +
> +	data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1;
> +
> +	if (is_inline(skb, &fragptr)) {
> +		tx_info->inl = 1;
> +	} else {
> +		/* Map fragments */
> +		for (i = skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) {
> +			frag = &skb_shinfo(skb)->frags[i];
> +			dma = skb_frag_dma_map(priv->ddev, frag,
> +					       0, skb_frag_size(frag),
> +					       DMA_TO_DEVICE);
> +			if (dma_mapping_error(priv->ddev, dma)) {

				goto err_unmap_frags;

You have a lot of huge scope variables. At least use these to hide
the 80 cols problems.

> +				for (i++; i < skb_shinfo(skb)->nr_frags; i++) {
> +					frag = &skb_shinfo(skb)->frags[i];
> +					en_err(priv, "DMA mapping error\n");
> +					dma_unmap_page(priv->ddev,
> +						       (dma_addr_t) be64_to_cpu(data[i].addr),
> +						       skb_frag_size(frag), PCI_DMA_TODEVICE);
> +				}
> +				goto tx_drop;
> +			}
> +
> +			data->addr = cpu_to_be64(dma);
> +			data->lkey = cpu_to_be32(mdev->mr.key);
> +			wmb();
> +			data->byte_count = cpu_to_be32(skb_frag_size(frag));
> +			--data;
> +		}
> +
> +		/* Map linear part */
> +		if (tx_info->linear) {
> +			u32 byte_count = skb_headlen(skb) - lso_header_size;
> +			dma = dma_map_single(priv->ddev, skb->data +
> +					     lso_header_size, byte_count,
> +					     PCI_DMA_TODEVICE);
> +			if (dma_mapping_error(priv->ddev, dma))
> +				goto tx_drop;

(frags dma leak)
				goto err_unmap_frags;

You may consider a local variable for 'priv->ddev' btw.

-- 
Ueimor

^ permalink raw reply

* [PATCH net] packet: restore packet statistics tp_packets to include drops
From: Willem de Bruijn @ 2013-08-19 20:40 UTC (permalink / raw)
  To: davem, dborkman, netdev, sergei.shtylyov; +Cc: Willem de Bruijn
In-Reply-To: <5212625A.1090704@cogentembedded.com>

getsockopt PACKET_STATISTICS returns tp_packets + tp_drops. Commit
ee80fbf301 ("packet: account statistics only in tpacket_stats_u")
cleaned up the getsockopt PACKET_STATISTICS code.
This also changed semantics. Historically, tp_packets included
tp_drops on return. The commit removed the line that adds tp_drops
into tp_packets.

This patch reinstates the old semantics.

Signed-off-by: Willem de Bruijn <willemb@google.com>

---

v2: incorporated commit summary by request. no code changes
---
 net/packet/af_packet.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6c53dd9..1fdf9ab 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3215,9 +3215,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
 
 		if (po->tp_version == TPACKET_V3) {
 			lv = sizeof(struct tpacket_stats_v3);
+			st.stats3.tp_packets += st.stats3.tp_drops;
 			data = &st.stats3;
 		} else {
 			lv = sizeof(struct tpacket_stats);
+			st.stats1.tp_packets += st.stats1.tp_drops;
 			data = &st.stats1;
 		}
 
-- 
1.8.3

^ permalink raw reply related

* [PATCH] Fix stack corruption on some architectures
From: Daniel Gimpelevich @ 2013-08-19 20:37 UTC (permalink / raw)
  To: Jan Dumon, Greg Kroah-Hartman, linux-usb, netdev, linux-kernel

There is no need to get an interface specification if we know it's the
wrong one; trivial change. The big thing, though, was explained in the
#mipslinux IRC channel: 
[Mon 2013-08-19 12:28:21 PM PDT] <headless> guys, are you sure it's not "DMA off stack" case?
[Mon 2013-08-19 12:28:35 PM PDT] <headless> it's a known stack corruptor on non-coherent arches
[Mon 2013-08-19 12:31:48 PM PDT] <DonkeyHotei> headless: for usb/ehci?
[Mon 2013-08-19 12:34:11 PM PDT] <DonkeyHotei> headless: explain
[Mon 2013-08-19 12:35:38 PM PDT] <headless> usb_control_msg() (or other such func) should not use buffer on stack. DMA from/to stack is prohibited
[Mon 2013-08-19 12:35:58 PM PDT] <headless> and EHCI uses DMA on control xfers (as well as all the others)

Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
---
 drivers/net/usb/hso.c |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cba1d46..86292e6 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2816,13 +2816,16 @@ exit:
 static int hso_get_config_data(struct usb_interface *interface)
 {
 	struct usb_device *usbdev = interface_to_usbdev(interface);
-	u8 config_data[17];
+	u8 *config_data = kmalloc(17, GFP_KERNEL);
 	u32 if_num = interface->altsetting->desc.bInterfaceNumber;
 	s32 result;
 
+	if (!config_data)
+		return -ENOMEM;
 	if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			    0x86, 0xC0, 0, 0, config_data, 17,
 			    USB_CTRL_SET_TIMEOUT) != 0x11) {
+		kfree(config_data);
 		return -EIO;
 	}
 
@@ -2873,6 +2876,7 @@ static int hso_get_config_data(struct usb_interface *interface)
 	if (config_data[16] & 0x1)
 		result |= HSO_INFO_CRC_BUG;
 
+	kfree(config_data);
 	return result;
 }
 
@@ -2886,6 +2890,11 @@ static int hso_probe(struct usb_interface *interface,
 	struct hso_shared_int *shared_int;
 	struct hso_device *tmp_dev = NULL;
 
+	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
+		dev_err(&interface->dev, "Not our interface\n");
+		return -ENODEV;
+	}
+
 	if_num = interface->altsetting->desc.bInterfaceNumber;
 
 	/* Get the interface/port specification from either driver_info or from
@@ -2895,10 +2904,6 @@ static int hso_probe(struct usb_interface *interface,
 	else
 		port_spec = hso_get_config_data(interface);
 
-	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
-		dev_err(&interface->dev, "Not our interface\n");
-		return -ENODEV;
-	}
 	/* Check if we need to switch to alt interfaces prior to port
 	 * configuration */
 	if (interface->num_altsetting > 1)
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH] Passing sk_buff metadata information to user space in TUNTAP driver.
From: Valas Valancius @ 2013-08-19 20:29 UTC (permalink / raw)
  To: Valas Valancius, David S. Miller
  Cc: Eric Dumazet, Maciej Żenczykowski, netdev

From: Valas Valancius <valas@google.com>

This patch introduces an optional metadata header to TUNTAP driver to pass
sk_buff information to user space. The patch currently enables passing
of skb->mark field and allows for easy expansion to add more sk_buff
fields later.

Tested: Compiled, booted. Process 1: openend TAP interface, enabled metadata
header on that interface. Process 2: opened a socket, set fwmark with SO_MARK
sock option, send packets, observed mark to propagate in Process 1.

Change-Id: I5d00522e9c4d9c1b57b4f4ac55c419a85de35dae
---
 drivers/net/tun.c           | 64 ++++++++++++++++++++++++++++++++++++++++++++-
 include/uapi/linux/if_tun.h |  7 +++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 978d865..f997d59 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -103,6 +103,15 @@ do {								\
 
 #define GOODCOPY_LEN 128
 
+/* Metadata header structure. */
+struct tun_meta_header {
+	/* struct sk_buff.mark */
+	int mark;
+};
+
+#define TUN_META_HDR_SZ sizeof(struct tun_meta_header)
+#define TUN_META_MARK_OFFSET offsetof(struct tun_meta_header, mark)
+
 #define FLT_EXACT_COUNT 8
 struct tap_filter {
 	unsigned int    count;    /* Number of addrs. Zero means disabled */
@@ -1227,6 +1236,20 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 		total += tun->vnet_hdr_sz;
 	}
 
+	if (tun->flags & TUN_META_HDR) {
+		struct tun_meta_header meta = { 0 };
+		len -= TUN_META_HDR_SZ;
+		if (len < 0)
+			return -EINVAL;
+
+		meta.mark = skb->mark;
+
+		if (unlikely(memcpy_toiovecend(iv, (void *)&meta, total,
+					       sizeof(meta))))
+			return -EFAULT;
+		total += TUN_META_HDR_SZ;
+	}
+
 	if (!vlan_tx_tag_present(skb)) {
 		len = min_t(int, skb->len, len);
 	} else {
@@ -1487,6 +1510,9 @@ static int tun_flags(struct tun_struct *tun)
 	if (tun->flags & TUN_PERSIST)
 		flags |= IFF_PERSIST;
 
+	if (tun->flags & TUN_META_HDR)
+		flags |= IFF_META_HDR;
+
 	return flags;
 }
 
@@ -1666,6 +1692,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 	else
 		tun->flags &= ~TUN_TAP_MQ;
 
+	if (ifr->ifr_flags & IFF_META_HDR)
+		tun->flags |= TUN_META_HDR;
+	else
+		tun->flags &= ~TUN_META_HDR;
+
 	/* Make sure persistent devices do not get stuck in
 	 * xoff state.
 	 */
@@ -1815,6 +1846,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 	kgid_t group;
 	int sndbuf;
 	int vnet_hdr_sz;
+	int tun_meta_param;
+	int tun_meta_value;
 	int ret;
 
 	if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) {
@@ -1828,7 +1861,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		 * This is needed because we never checked for invalid flags on
 		 * TUNSETIFF. */
 		return put_user(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
-				IFF_VNET_HDR | IFF_MULTI_QUEUE,
+				IFF_VNET_HDR | IFF_MULTI_QUEUE | IFF_META_HDR,
 				(unsigned int __user*)argp);
 	} else if (cmd == TUNSETQUEUE)
 		return tun_set_queue(file, &ifr);
@@ -1996,6 +2029,35 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		tun->vnet_hdr_sz = vnet_hdr_sz;
 		break;
 
+	case TUNGETMETAPARAM:
+		if (copy_from_user(&tun_meta_param, argp,
+				   sizeof(tun_meta_param))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		ret = 0;
+		switch (tun_meta_param) {
+		case TUN_GET_META_HDR_SZ:
+			tun_meta_value = TUN_META_HDR_SZ;
+			break;
+
+		case TUN_GET_META_MARK_OFFSET:
+			tun_meta_value = TUN_META_MARK_OFFSET;
+			break;
+
+		default:
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!ret)
+			if (copy_to_user(argp, &tun_meta_value,
+					 sizeof(tun_meta_value)))
+				ret = -EFAULT;
+		break;
+
+
 	case TUNATTACHFILTER:
 		/* Can be set only for TAPs */
 		ret = -EINVAL;
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h
index 1870ee2..26e6c9e 100644
--- a/include/uapi/linux/if_tun.h
+++ b/include/uapi/linux/if_tun.h
@@ -36,6 +36,7 @@
 #define TUN_PERSIST 	0x0100	
 #define TUN_VNET_HDR 	0x0200
 #define TUN_TAP_MQ      0x0400
+#define TUN_META_HDR	0x0800
 
 /* Ioctl defines */
 #define TUNSETNOCSUM  _IOW('T', 200, int) 
@@ -56,10 +57,12 @@
 #define TUNGETVNETHDRSZ _IOR('T', 215, int)
 #define TUNSETVNETHDRSZ _IOW('T', 216, int)
 #define TUNSETQUEUE  _IOW('T', 217, int)
+#define TUNGETMETAPARAM _IOR('T', 218, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TUN		0x0001
 #define IFF_TAP		0x0002
+#define IFF_META_HDR	0x0004
 #define IFF_NO_PI	0x1000
 /* This flag has no real effect */
 #define IFF_ONE_QUEUE	0x2000
@@ -103,4 +106,8 @@ struct tun_filter {
 	__u8   addr[0][ETH_ALEN];
 };
 
+/* TUNGETMETAPARAM metadata header request types. */
+#define TUN_GET_META_HDR_SZ 0
+#define TUN_GET_META_MARK_OFFSET 1
+
 #endif /* _UAPI__IF_TUN_H */
-- 
1.8.3

^ permalink raw reply related

* Re: [PATCHv2] net: cpsw: Add support for wake-on-lan for cpsw
From: Francois Romieu @ 2013-08-19 20:15 UTC (permalink / raw)
  To: ujhelyi.m; +Cc: davem, mugunthanvnm, netdev, linux-kernel
In-Reply-To: <1376910358-19882-1-git-send-email-ujhelyi.m@gmail.com>

ujhelyi.m@gmail.com <ujhelyi.m@gmail.com> :
[...]
> Some phy's can be configured to enable wake on lan (e.g. at803x or marvell 88E1318S).
> There is no way how to enable wol on CPSW with such connected phys. This patch
> adds this support. It is provided by calling the phy's related code.
> 
> Tested on board with at8030x connected phy. Wol interrupt line is
> connected to GPIO0 on am335x.

This patch adds a feature. It isn't a bugfix. It should thus target
'net-next', not 'net' (it does not apply to net-next as of 2ff1cf12c9 btw).

> 
> Signed-off-by: Matus Ujhelyi <ujhelyi.m@gmail.com>
> ---
>  drivers/net/ethernet/ti/cpsw.c |   23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
> index 22a7a43..fe8d973 100644
> --- a/drivers/net/ethernet/ti/cpsw.c
> +++ b/drivers/net/ethernet/ti/cpsw.c
> @@ -1416,6 +1416,27 @@ static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
>  		return -EOPNOTSUPP;
>  }
>  
> +static void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +	int slave_no = cpsw_slave_index(priv);
> +	wol->supported = 0;

Variable declarations and code should be separated: please add an empty
line.

> +	wol->wolopts = 0;
> +	if (priv->slaves[slave_no].phy)
> +		phy_ethtool_get_wol(priv->slaves[slave_no].phy, wol);
> +
> +}

Useless empty line.

> +
> +static int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +	int slave_no = cpsw_slave_index(priv);
> +	if (priv->slaves[slave_no].phy)

Variable declarations and code should be separated: please add an empty
line.

> +		return phy_ethtool_set_wol(priv->slaves[slave_no].phy, wol);
> +	else
> +		return -EOPNOTSUPP;
> +}
> +
>  static const struct ethtool_ops cpsw_ethtool_ops = {
>  	.get_drvinfo	= cpsw_get_drvinfo,
>  	.get_msglevel	= cpsw_get_msglevel,
> @@ -1426,6 +1447,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
>  	.set_settings	= cpsw_set_settings,
>  	.get_coalesce	= cpsw_get_coalesce,
                     ^^^ tab
>  	.set_coalesce	= cpsw_set_coalesce,
                     ^^^ tab
> +	.get_wol        = cpsw_get_wol,
                ^^^^^^^^  spaces, please use tabs.
> +	.set_wol        = cpsw_set_wol,
                ^^^^^^^^  spaces, please use tabs.

-- 
Ueimor

^ permalink raw reply

* Re: NAT stops forwarding ACKs after PMTU discovery
From: Jozsef Kadlecsik @ 2013-08-19 20:13 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Christoph Paasch, Corey Hickey, Linux Netdev List,
	netfilter-devel
In-Reply-To: <1376920685.4226.61.camel@edumazet-glaptop>

On Mon, 19 Aug 2013, Eric Dumazet wrote:

> On Mon, 2013-08-19 at 15:49 +0200, Christoph Paasch wrote:
>
> > It's a TCP-patch, that interprets duplicate-acks with invalid SACK-blocks as
> > duplicate acks in tcp_sock->sacked_out.
> 
> Yeah, but here, this is conntrack who is blocking the thing.
> 
> TCP receiver has no chance to 'fix' it.
> 
> See conntrack is one of those buggy middle box as well.
> 
> So if you want to properly handle this mess, you'll also have to fix
> conntrack.

I beg you pardon: why conntrack should be relaxed, when it is expected
to do more strict TCP checkings (RFC5961, Section 5.).

Also, it's clearly a broken middle box. Don't shoot the messenger.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply

* heavily backlogged...
From: David Miller @ 2013-08-19 19:52 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netfilter-devel-u79uwXL29TY76Z2rM5mHXA


Due to the weekend vger.kernel.org mail issues I haven't been able
to read my own email until just now.

So I've got a 9000+ email backlog to sift through because I can
do anything useful.

Thanks for your patience in advance.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [Patch net-next v3 9/9] selinux: use generic union inet_addr
From: David Miller @ 2013-08-19 19:50 UTC (permalink / raw)
  To: casey
  Cc: amwang, netdev, james.l.morris, sds, eparis, pmoore, linux-kernel,
	linux-security-module
In-Reply-To: <52127336.3080209@schaufler-ca.com>


It's so that you can pass a generic ipv4/ipv6 address blob into
things like printf formatting, and since there is an address family
member present, it knows what's in there and therefore one printf
format specifier can handle both ipv4 and ipv6 addresses.

Like you, I think these changes a complete waste of time too, I'm just
relaying what I was told.

^ permalink raw reply

* Re: [Patch net-next v3 9/9] selinux: use generic union inet_addr
From: Casey Schaufler @ 2013-08-19 19:34 UTC (permalink / raw)
  To: Cong Wang
  Cc: netdev, David S. Miller, James Morris, Stephen Smalley,
	Eric Paris, Paul Moore, linux-kernel, linux-security-module
In-Reply-To: <1376907278-26377-10-git-send-email-amwang@redhat.com>

On 8/19/2013 3:14 AM, Cong Wang wrote:
> From: Cong Wang <amwang@redhat.com>
>
> selinux has some similar definition like union inet_addr,
> it can re-use the generic union inet_addr too.

I'm trying to understand what value this change adds.
All it appears to do is swap one set of inconvenient
structure members for a different set of inconvenient
structure members. Does it improve performance?


>
> Cc: James Morris <james.l.morris@oracle.com>
> Cc: Stephen Smalley <sds@tycho.nsa.gov>
> Cc: Eric Paris <eparis@parisplace.org>
> Cc: Paul Moore <pmoore@redhat.com>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-security-module@vger.kernel.org
> Signed-off-by: Cong Wang <amwang@redhat.com>
> ---
>  include/linux/lsm_audit.h          |   19 +-----
>  security/lsm_audit.c               |   58 ++++++++--------
>  security/selinux/hooks.c           |  130 +++++++++++++++++-------------------
>  security/selinux/include/netnode.h |    4 +-
>  security/selinux/include/objsec.h  |    7 +--
>  security/selinux/netnode.c         |  102 ++++++++--------------------
>  security/smack/smack_lsm.c         |   19 +++---
>  7 files changed, 138 insertions(+), 201 deletions(-)
>
> diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h
> index 1cc89e9..48cab1e 100644
> --- a/include/linux/lsm_audit.h
> +++ b/include/linux/lsm_audit.h
> @@ -21,23 +21,13 @@
>  #include <linux/path.h>
>  #include <linux/key.h>
>  #include <linux/skbuff.h>
> +#include <net/inet_addr.h>
>  
>  struct lsm_network_audit {
>  	int netif;
>  	struct sock *sk;
> -	u16 family;
> -	__be16 dport;
> -	__be16 sport;
> -	union {
> -		struct {
> -			__be32 daddr;
> -			__be32 saddr;
> -		} v4;
> -		struct {
> -			struct in6_addr daddr;
> -			struct in6_addr saddr;
> -		} v6;
> -	} fam;
> +	union inet_addr saddr;
> +	union inet_addr daddr;
>  };
>  
>  /* Auxiliary data to use in generating the audit record. */
> @@ -83,9 +73,6 @@ struct common_audit_data {
>  	}; /* per LSM data pointer union */
>  };
>  
> -#define v4info fam.v4
> -#define v6info fam.v6
> -
>  int ipv4_skb_to_auditdata(struct sk_buff *skb,
>  		struct common_audit_data *ad, u8 *proto);
>  
> diff --git a/security/lsm_audit.c b/security/lsm_audit.c
> index 8d8d97d..244c2a1 100644
> --- a/security/lsm_audit.c
> +++ b/security/lsm_audit.c
> @@ -49,8 +49,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
>  	if (ih == NULL)
>  		return -EINVAL;
>  
> -	ad->u.net->v4info.saddr = ih->saddr;
> -	ad->u.net->v4info.daddr = ih->daddr;
> +	ad->u.net->saddr.sin.sin_addr.s_addr = ih->saddr;
> +	ad->u.net->daddr.sin.sin_addr.s_addr = ih->daddr;
>  
>  	if (proto)
>  		*proto = ih->protocol;
> @@ -64,8 +64,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
>  		if (th == NULL)
>  			break;
>  
> -		ad->u.net->sport = th->source;
> -		ad->u.net->dport = th->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(th->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(th->dest));
>  		break;
>  	}
>  	case IPPROTO_UDP: {
> @@ -73,8 +73,8 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
>  		if (uh == NULL)
>  			break;
>  
> -		ad->u.net->sport = uh->source;
> -		ad->u.net->dport = uh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(uh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(uh->dest));
>  		break;
>  	}
>  	case IPPROTO_DCCP: {
> @@ -82,16 +82,16 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
>  		if (dh == NULL)
>  			break;
>  
> -		ad->u.net->sport = dh->dccph_sport;
> -		ad->u.net->dport = dh->dccph_dport;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(dh->dccph_sport));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(dh->dccph_dport));
>  		break;
>  	}
>  	case IPPROTO_SCTP: {
>  		struct sctphdr *sh = sctp_hdr(skb);
>  		if (sh == NULL)
>  			break;
> -		ad->u.net->sport = sh->source;
> -		ad->u.net->dport = sh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(sh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(sh->dest));
>  		break;
>  	}
>  	default:
> @@ -119,8 +119,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
>  	ip6 = ipv6_hdr(skb);
>  	if (ip6 == NULL)
>  		return -EINVAL;
> -	ad->u.net->v6info.saddr = ip6->saddr;
> -	ad->u.net->v6info.daddr = ip6->daddr;
> +	ad->u.net->saddr.sin6.sin6_addr = ip6->saddr;
> +	ad->u.net->daddr.sin6.sin6_addr = ip6->daddr;
>  	ret = 0;
>  	/* IPv6 can have several extension header before the Transport header
>  	 * skip them */
> @@ -140,8 +140,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
>  		if (th == NULL)
>  			break;
>  
> -		ad->u.net->sport = th->source;
> -		ad->u.net->dport = th->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(th->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(th->dest));
>  		break;
>  	}
>  	case IPPROTO_UDP: {
> @@ -151,8 +151,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
>  		if (uh == NULL)
>  			break;
>  
> -		ad->u.net->sport = uh->source;
> -		ad->u.net->dport = uh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(uh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(uh->dest));
>  		break;
>  	}
>  	case IPPROTO_DCCP: {
> @@ -162,8 +162,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
>  		if (dh == NULL)
>  			break;
>  
> -		ad->u.net->sport = dh->dccph_sport;
> -		ad->u.net->dport = dh->dccph_dport;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(dh->dccph_sport));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(dh->dccph_dport));
>  		break;
>  	}
>  	case IPPROTO_SCTP: {
> @@ -172,8 +172,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
>  		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
>  		if (sh == NULL)
>  			break;
> -		ad->u.net->sport = sh->source;
> -		ad->u.net->dport = sh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(sh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(sh->dest));
>  		break;
>  	}
>  	default:
> @@ -333,21 +333,21 @@ static void dump_common_audit_data(struct audit_buffer *ab,
>  			}
>  		}
>  
> -		switch (a->u.net->family) {
> +		switch (a->u.net->saddr.sa.sa_family) {
>  		case AF_INET:
> -			print_ipv4_addr(ab, a->u.net->v4info.saddr,
> -					a->u.net->sport,
> +			print_ipv4_addr(ab, a->u.net->saddr.sin.sin_addr.s_addr,
> +					a->u.net->saddr.sin.sin_port,
>  					"saddr", "src");
> -			print_ipv4_addr(ab, a->u.net->v4info.daddr,
> -					a->u.net->dport,
> +			print_ipv4_addr(ab, a->u.net->daddr.sin.sin_addr.s_addr,
> +					a->u.net->daddr.sin.sin_port,
>  					"daddr", "dest");
>  			break;
>  		case AF_INET6:
> -			print_ipv6_addr(ab, &a->u.net->v6info.saddr,
> -					a->u.net->sport,
> +			print_ipv6_addr(ab, &a->u.net->saddr.sin6.sin6_addr,
> +					a->u.net->saddr.sin.sin_port,
>  					"saddr", "src");
> -			print_ipv6_addr(ab, &a->u.net->v6info.daddr,
> -					a->u.net->dport,
> +			print_ipv6_addr(ab, &a->u.net->daddr.sin6.sin6_addr,
> +					a->u.net->daddr.sin.sin_port,
>  					"daddr", "dest");
>  			break;
>  		}
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index c956390..f9959c0 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3595,8 +3595,8 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
>  	if (ihlen < sizeof(_iph))
>  		goto out;
>  
> -	ad->u.net->v4info.saddr = ih->saddr;
> -	ad->u.net->v4info.daddr = ih->daddr;
> +	ad->u.net->saddr.sin.sin_addr.s_addr = ih->saddr;
> +	ad->u.net->daddr.sin.sin_addr.s_addr = ih->daddr;
>  	ret = 0;
>  
>  	if (proto)
> @@ -3614,8 +3614,8 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
>  		if (th == NULL)
>  			break;
>  
> -		ad->u.net->sport = th->source;
> -		ad->u.net->dport = th->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(th->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(th->dest));
>  		break;
>  	}
>  
> @@ -3630,8 +3630,8 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
>  		if (uh == NULL)
>  			break;
>  
> -		ad->u.net->sport = uh->source;
> -		ad->u.net->dport = uh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(uh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(uh->dest));
>  		break;
>  	}
>  
> @@ -3646,8 +3646,8 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
>  		if (dh == NULL)
>  			break;
>  
> -		ad->u.net->sport = dh->dccph_sport;
> -		ad->u.net->dport = dh->dccph_dport;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(dh->dccph_sport));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(dh->dccph_dport));
>  		break;
>  	}
>  
> @@ -3674,8 +3674,8 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
>  	if (ip6 == NULL)
>  		goto out;
>  
> -	ad->u.net->v6info.saddr = ip6->saddr;
> -	ad->u.net->v6info.daddr = ip6->daddr;
> +	ad->u.net->saddr.sin6.sin6_addr = ip6->saddr;
> +	ad->u.net->daddr.sin6.sin6_addr = ip6->daddr;
>  	ret = 0;
>  
>  	nexthdr = ip6->nexthdr;
> @@ -3695,8 +3695,8 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
>  		if (th == NULL)
>  			break;
>  
> -		ad->u.net->sport = th->source;
> -		ad->u.net->dport = th->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(th->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(th->dest));
>  		break;
>  	}
>  
> @@ -3707,8 +3707,8 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
>  		if (uh == NULL)
>  			break;
>  
> -		ad->u.net->sport = uh->source;
> -		ad->u.net->dport = uh->dest;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(uh->source));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(uh->dest));
>  		break;
>  	}
>  
> @@ -3719,8 +3719,8 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
>  		if (dh == NULL)
>  			break;
>  
> -		ad->u.net->sport = dh->dccph_sport;
> -		ad->u.net->dport = dh->dccph_dport;
> +		inet_addr_set_port(&ad->u.net->saddr, ntohs(dh->dccph_sport));
> +		inet_addr_set_port(&ad->u.net->daddr, ntohs(dh->dccph_dport));
>  		break;
>  	}
>  
> @@ -3735,18 +3735,17 @@ out:
>  #endif /* IPV6 */
>  
>  static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
> -			     char **_addrp, int src, u8 *proto)
> +			     union inet_addr **_addrp, int src, u8 *proto)
>  {
> -	char *addrp;
> +	union inet_addr *addrp;
>  	int ret;
> +	sa_family_t family = src ? ad->u.net->saddr.sa.sa_family : ad->u.net->daddr.sa.sa_family;
>  
> -	switch (ad->u.net->family) {
> +	switch (family) {
>  	case PF_INET:
>  		ret = selinux_parse_skb_ipv4(skb, ad, proto);
>  		if (ret)
>  			goto parse_error;
> -		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
> -				       &ad->u.net->v4info.daddr);
>  		goto okay;
>  
>  #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
> @@ -3754,13 +3753,11 @@ static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
>  		ret = selinux_parse_skb_ipv6(skb, ad, proto);
>  		if (ret)
>  			goto parse_error;
> -		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
> -				       &ad->u.net->v6info.daddr);
>  		goto okay;
>  #endif	/* IPV6 */
>  	default:
>  		addrp = NULL;
> -		goto okay;
> +		goto save;
>  	}
>  
>  parse_error:
> @@ -3770,6 +3767,8 @@ parse_error:
>  	return ret;
>  
>  okay:
> +	addrp = src ? &ad->u.net->saddr : &ad->u.net->daddr;
> +save:
>  	if (_addrp)
>  		*_addrp = addrp;
>  	return 0;
> @@ -3912,25 +3911,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
>  	 */
>  	family = sk->sk_family;
>  	if (family == PF_INET || family == PF_INET6) {
> -		char *addrp;
> +		union inet_addr *addrp = (union inet_addr *)address;
>  		struct sk_security_struct *sksec = sk->sk_security;
>  		struct common_audit_data ad;
>  		struct lsm_network_audit net = {0,};
> -		struct sockaddr_in *addr4 = NULL;
> -		struct sockaddr_in6 *addr6 = NULL;
>  		unsigned short snum;
>  		u32 sid, node_perm;
>  
> -		if (family == PF_INET) {
> -			addr4 = (struct sockaddr_in *)address;
> -			snum = ntohs(addr4->sin_port);
> -			addrp = (char *)&addr4->sin_addr.s_addr;
> -		} else {
> -			addr6 = (struct sockaddr_in6 *)address;
> -			snum = ntohs(addr6->sin6_port);
> -			addrp = (char *)&addr6->sin6_addr.s6_addr;
> -		}
> -
> +		addrp->sa.sa_family = family;
> +		snum = inet_addr_get_port(addrp);
>  		if (snum) {
>  			int low, high;
>  
> @@ -3943,8 +3932,9 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
>  					goto out;
>  				ad.type = LSM_AUDIT_DATA_NET;
>  				ad.u.net = &net;
> -				ad.u.net->sport = htons(snum);
> -				ad.u.net->family = family;
> +				inet_addr_set_port(&ad.u.net->saddr, snum);
> +				ad.u.net->saddr.sa.sa_family = family;
> +				ad.u.net->daddr.sa.sa_family = family;
>  				err = avc_has_perm(sksec->sid, sid,
>  						   sksec->sclass,
>  						   SOCKET__NAME_BIND, &ad);
> @@ -3971,19 +3961,17 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
>  			break;
>  		}
>  
> -		err = sel_netnode_sid(addrp, family, &sid);
> +		err = sel_netnode_sid(addrp, &sid);
>  		if (err)
>  			goto out;
>  
>  		ad.type = LSM_AUDIT_DATA_NET;
>  		ad.u.net = &net;
> -		ad.u.net->sport = htons(snum);
> -		ad.u.net->family = family;
> +		inet_addr_set_port(&ad.u.net->saddr, snum);
> +		ad.u.net->saddr.sa.sa_family = family;
> +		ad.u.net->daddr.sa.sa_family = family;
>  
> -		if (family == PF_INET)
> -			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
> -		else
> -			ad.u.net->v6info.saddr = addr6->sin6_addr;
> +		ad.u.net->saddr = *addrp;
>  
>  		err = avc_has_perm(sksec->sid, sid,
>  				   sksec->sclass, node_perm, &ad);
> @@ -4011,22 +3999,18 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
>  	    sksec->sclass == SECCLASS_DCCP_SOCKET) {
>  		struct common_audit_data ad;
>  		struct lsm_network_audit net = {0,};
> -		struct sockaddr_in *addr4 = NULL;
> -		struct sockaddr_in6 *addr6 = NULL;
> +		union inet_addr *addrp = (union inet_addr *)address;
>  		unsigned short snum;
>  		u32 sid, perm;
>  
>  		if (sk->sk_family == PF_INET) {
> -			addr4 = (struct sockaddr_in *)address;
>  			if (addrlen < sizeof(struct sockaddr_in))
>  				return -EINVAL;
> -			snum = ntohs(addr4->sin_port);
>  		} else {
> -			addr6 = (struct sockaddr_in6 *)address;
>  			if (addrlen < SIN6_LEN_RFC2133)
>  				return -EINVAL;
> -			snum = ntohs(addr6->sin6_port);
>  		}
> +		snum = inet_addr_get_port(addrp);
>  
>  		err = sel_netport_sid(sk->sk_protocol, snum, &sid);
>  		if (err)
> @@ -4037,8 +4021,9 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
>  
>  		ad.type = LSM_AUDIT_DATA_NET;
>  		ad.u.net = &net;
> -		ad.u.net->dport = htons(snum);
> -		ad.u.net->family = sk->sk_family;
> +		inet_addr_set_port(&ad.u.net->daddr, snum);
> +		ad.u.net->saddr.sa.sa_family = sk->sk_family;
> +		ad.u.net->daddr.sa.sa_family = sk->sk_family;
>  		err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
>  		if (err)
>  			goto out;
> @@ -4169,7 +4154,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
>  			    &ad);
>  }
>  
> -static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
> +static int selinux_inet_sys_rcv_skb(int ifindex, union inet_addr *addrp,
>  				    u32 peer_sid,
>  				    struct common_audit_data *ad)
>  {
> @@ -4185,7 +4170,7 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
>  	if (err)
>  		return err;
>  
> -	err = sel_netnode_sid(addrp, family, &node_sid);
> +	err = sel_netnode_sid(addrp, &node_sid);
>  	if (err)
>  		return err;
>  	return avc_has_perm(peer_sid, node_sid,
> @@ -4200,12 +4185,13 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
>  	u32 sk_sid = sksec->sid;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> -	char *addrp;
> +	union inet_addr *addrp;
>  
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
>  	ad.u.net->netif = skb->skb_iif;
> -	ad.u.net->family = family;
> +	ad.u.net->saddr.sa.sa_family = family;
> +	ad.u.net->daddr.sa.sa_family = family;
>  	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
>  	if (err)
>  		return err;
> @@ -4233,7 +4219,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  	u32 sk_sid = sksec->sid;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> -	char *addrp;
> +	union inet_addr *addrp;
>  	u8 secmark_active;
>  	u8 peerlbl_active;
>  
> @@ -4259,7 +4245,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
>  	ad.u.net->netif = skb->skb_iif;
> -	ad.u.net->family = family;
> +	ad.u.net->saddr.sa.sa_family = family;
> +	ad.u.net->daddr.sa.sa_family = family;
>  	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
>  	if (err)
>  		return err;
> @@ -4270,7 +4257,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
>  		if (err)
>  			return err;
> -		err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
> +		addrp->sa.sa_family = family;
> +		err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp,
>  					       peer_sid, &ad);
>  		if (err) {
>  			selinux_netlbl_err(skb, err, 0);
> @@ -4621,7 +4609,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
>  				       u16 family)
>  {
>  	int err;
> -	char *addrp;
> +	union inet_addr *addrp;
>  	u32 peer_sid;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> @@ -4644,12 +4632,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
>  	ad.u.net->netif = ifindex;
> -	ad.u.net->family = family;
> +	ad.u.net->saddr.sa.sa_family = family;
> +	ad.u.net->daddr.sa.sa_family = family;
>  	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
>  		return NF_DROP;
>  
>  	if (peerlbl_active) {
> -		err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
> +		addrp->sa.sa_family = family;
> +		err = selinux_inet_sys_rcv_skb(ifindex, addrp,
>  					       peer_sid, &ad);
>  		if (err) {
>  			selinux_netlbl_err(skb, err, 1);
> @@ -4732,7 +4722,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
>  	struct sk_security_struct *sksec;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> -	char *addrp;
> +	union inet_addr *addrp;
>  	u8 proto;
>  
>  	if (sk == NULL)
> @@ -4742,7 +4732,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
>  	ad.u.net->netif = ifindex;
> -	ad.u.net->family = family;
> +	ad.u.net->saddr.sa.sa_family = family;
> +	ad.u.net->daddr.sa.sa_family = family;
>  	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
>  		return NF_DROP;
>  
> @@ -4765,7 +4756,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
>  	struct sock *sk;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> -	char *addrp;
> +	union inet_addr *addrp;
>  	u8 secmark_active;
>  	u8 peerlbl_active;
>  
> @@ -4813,7 +4804,8 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
>  	ad.u.net->netif = ifindex;
> -	ad.u.net->family = family;
> +	ad.u.net->saddr.sa.sa_family = family;
> +	ad.u.net->daddr.sa.sa_family = family;
>  	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
>  		return NF_DROP;
>  
> @@ -4832,7 +4824,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
>  				 SECCLASS_NETIF, NETIF__EGRESS, &ad))
>  			return NF_DROP_ERR(-ECONNREFUSED);
>  
> -		if (sel_netnode_sid(addrp, family, &node_sid))
> +		if (sel_netnode_sid(addrp, &node_sid))
>  			return NF_DROP;
>  		if (avc_has_perm(peer_sid, node_sid,
>  				 SECCLASS_NODE, NODE__SENDTO, &ad))
> diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h
> index df7a5ed..f32c909 100644
> --- a/security/selinux/include/netnode.h
> +++ b/security/selinux/include/netnode.h
> @@ -27,6 +27,8 @@
>  #ifndef _SELINUX_NETNODE_H
>  #define _SELINUX_NETNODE_H
>  
> -int sel_netnode_sid(void *addr, u16 family, u32 *sid);
> +#include <net/inet_addr.h>
> +
> +int sel_netnode_sid(union inet_addr *addr, u32 *sid);
>  
>  #endif
> diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
> index aa47bca..a46caaf 100644
> --- a/security/selinux/include/objsec.h
> +++ b/security/selinux/include/objsec.h
> @@ -24,6 +24,7 @@
>  #include <linux/binfmts.h>
>  #include <linux/in.h>
>  #include <linux/spinlock.h>
> +#include <net/inet_addr.h>
>  #include "flask.h"
>  #include "avc.h"
>  
> @@ -80,12 +81,8 @@ struct netif_security_struct {
>  };
>  
>  struct netnode_security_struct {
> -	union {
> -		__be32 ipv4;		/* IPv4 node address */
> -		struct in6_addr ipv6;	/* IPv6 node address */
> -	} addr;
> +	union inet_addr addr;
>  	u32 sid;			/* SID for this node */
> -	u16 family;			/* address family */
>  };
>  
>  struct netport_security_struct {
> diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
> index c5454c0..713f14e 100644
> --- a/security/selinux/netnode.c
> +++ b/security/selinux/netnode.c
> @@ -68,79 +68,49 @@ static LIST_HEAD(sel_netnode_list);
>  static DEFINE_SPINLOCK(sel_netnode_lock);
>  static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
>  
> -/**
> - * sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table
> - * @addr: IPv4 address
> - *
> - * Description:
> - * This is the IPv4 hashing function for the node interface table, it returns
> - * the bucket number for the given IP address.
> - *
> - */
> -static unsigned int sel_netnode_hashfn_ipv4(__be32 addr)
> -{
> -	/* at some point we should determine if the mismatch in byte order
> -	 * affects the hash function dramatically */
> -	return (addr & (SEL_NETNODE_HASH_SIZE - 1));
> -}
>  
>  /**
> - * sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table
> - * @addr: IPv6 address
> + * sel_netnode_hashfn - IPv4/IPv6 hashing function for the node table
> + * @addr: generic IP address
>   *
>   * Description:
> - * This is the IPv6 hashing function for the node interface table, it returns
> + * This is the IP hashing function for the node interface table, it returns
>   * the bucket number for the given IP address.
>   *
>   */
> -static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
> +static unsigned int sel_netnode_hashfn(const union inet_addr *addr)
>  {
> -	/* just hash the least significant 32 bits to keep things fast (they
> -	 * are the most likely to be different anyway), we can revisit this
> -	 * later if needed */
> -	return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
> +	if (addr->sa.sa_family == PF_INET)
> +		/* at some point we should determine if the mismatch in byte order
> +		 * affects the hash function dramatically */
> +		return (addr->sin.sin_addr.s_addr & (SEL_NETNODE_HASH_SIZE - 1));
> +	else if (addr->sa.sa_family == PF_INET6)
> +		/* just hash the least significant 32 bits to keep things fast (they
> +		 * are the most likely to be different anyway), we can revisit this
> +		 * later if needed */
> +		return (addr->sin6.sin6_addr.s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
> +	else
> +		BUG();
>  }
>  
>  /**
>   * sel_netnode_find - Search for a node record
>   * @addr: IP address
> - * @family: address family
>   *
>   * Description:
>   * Search the network node table and return the record matching @addr.  If an
>   * entry can not be found in the table return NULL.
>   *
>   */
> -static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
> +static struct sel_netnode *sel_netnode_find(const union inet_addr *addr)
>  {
>  	unsigned int idx;
>  	struct sel_netnode *node;
>  
> -	switch (family) {
> -	case PF_INET:
> -		idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
> -		break;
> -	case PF_INET6:
> -		idx = sel_netnode_hashfn_ipv6(addr);
> -		break;
> -	default:
> -		BUG();
> -		return NULL;
> -	}
> -
> +	idx = sel_netnode_hashfn(addr);
>  	list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
> -		if (node->nsec.family == family)
> -			switch (family) {
> -			case PF_INET:
> -				if (node->nsec.addr.ipv4 == *(__be32 *)addr)
> -					return node;
> -				break;
> -			case PF_INET6:
> -				if (ipv6_addr_equal(&node->nsec.addr.ipv6,
> -						    addr))
> -					return node;
> -				break;
> -			}
> +		if (inet_addr_equal(&node->nsec.addr, addr))
> +			return node;
>  
>  	return NULL;
>  }
> @@ -156,18 +126,9 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
>  static void sel_netnode_insert(struct sel_netnode *node)
>  {
>  	unsigned int idx;
> +	union inet_addr *addr = &node->nsec.addr;
>  
> -	switch (node->nsec.family) {
> -	case PF_INET:
> -		idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
> -		break;
> -	case PF_INET6:
> -		idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
> -		break;
> -	default:
> -		BUG();
> -	}
> -
> +	idx = sel_netnode_hashfn(addr);
>  	/* we need to impose a limit on the growth of the hash table so check
>  	 * this bucket to make sure it is within the specified bounds */
>  	list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
> @@ -186,7 +147,6 @@ static void sel_netnode_insert(struct sel_netnode *node)
>  /**
>   * sel_netnode_sid_slow - Lookup the SID of a network address using the policy
>   * @addr: the IP address
> - * @family: the address family
>   * @sid: node SID
>   *
>   * Description:
> @@ -196,14 +156,14 @@ static void sel_netnode_insert(struct sel_netnode *node)
>   * failure.
>   *
>   */
> -static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
> +static int sel_netnode_sid_slow(union inet_addr *addr, u32 *sid)
>  {
>  	int ret = -ENOMEM;
>  	struct sel_netnode *node;
>  	struct sel_netnode *new = NULL;
>  
>  	spin_lock_bh(&sel_netnode_lock);
> -	node = sel_netnode_find(addr, family);
> +	node = sel_netnode_find(addr);
>  	if (node != NULL) {
>  		*sid = node->nsec.sid;
>  		spin_unlock_bh(&sel_netnode_lock);
> @@ -212,16 +172,16 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
>  	new = kzalloc(sizeof(*new), GFP_ATOMIC);
>  	if (new == NULL)
>  		goto out;
> -	switch (family) {
> +	switch (addr->sa.sa_family) {
>  	case PF_INET:
>  		ret = security_node_sid(PF_INET,
>  					addr, sizeof(struct in_addr), sid);
> -		new->nsec.addr.ipv4 = *(__be32 *)addr;
> +		new->nsec.addr = *addr;
>  		break;
>  	case PF_INET6:
>  		ret = security_node_sid(PF_INET6,
>  					addr, sizeof(struct in6_addr), sid);
> -		new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
> +		new->nsec.addr = *addr;
>  		break;
>  	default:
>  		BUG();
> @@ -229,7 +189,6 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
>  	if (ret != 0)
>  		goto out;
>  
> -	new->nsec.family = family;
>  	new->nsec.sid = *sid;
>  	sel_netnode_insert(new);
>  
> @@ -246,8 +205,7 @@ out:
>  
>  /**
>   * sel_netnode_sid - Lookup the SID of a network address
> - * @addr: the IP address
> - * @family: the address family
> + * @addr: the generic IP address
>   * @sid: node SID
>   *
>   * Description:
> @@ -258,12 +216,12 @@ out:
>   * on failure.
>   *
>   */
> -int sel_netnode_sid(void *addr, u16 family, u32 *sid)
> +int sel_netnode_sid(union inet_addr *addr, u32 *sid)
>  {
>  	struct sel_netnode *node;
>  
>  	rcu_read_lock();
> -	node = sel_netnode_find(addr, family);
> +	node = sel_netnode_find(addr);
>  	if (node != NULL) {
>  		*sid = node->nsec.sid;
>  		rcu_read_unlock();
> @@ -271,7 +229,7 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid)
>  	}
>  	rcu_read_unlock();
>  
> -	return sel_netnode_sid_slow(addr, family, sid);
> +	return sel_netnode_sid_slow(addr, sid);
>  }
>  
>  /**
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index eefbd10..9a80923 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -1900,9 +1900,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
>  		struct lsm_network_audit net;
>  
>  		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
> -		ad.a.u.net->family = sap->sin_family;
> -		ad.a.u.net->dport = sap->sin_port;
> -		ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
> +		ad.a.u.net->daddr = (union inet_addr )*sap;
>  #endif
>  		sk_lbl = SMACK_UNLABELED_SOCKET;
>  		skp = ssp->smk_out;
> @@ -2055,12 +2053,13 @@ auditout:
>  
>  #ifdef CONFIG_AUDIT
>  	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
> -	ad.a.u.net->family = sk->sk_family;
> -	ad.a.u.net->dport = port;
> +	inet_addr_set_port(&ad.a.u.net->daddr, port);
> +	ad.a.u.net->saddr.sa.sa_family = sk->sk_family;
> +	ad.a.u.net->daddr.sa.sa_family = sk->sk_family;
>  	if (act == SMK_RECEIVING)
> -		ad.a.u.net->v6info.saddr = address->sin6_addr;
> +		ad.a.u.net->saddr.sin6.sin6_addr = address->sin6_addr;
>  	else
> -		ad.a.u.net->v6info.daddr = address->sin6_addr;
> +		ad.a.u.net->daddr.sin6.sin6_addr = address->sin6_addr;
>  #endif
>  	return smk_access(skp, object, MAY_WRITE, &ad);
>  }
> @@ -3202,7 +3201,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  
>  #ifdef CONFIG_AUDIT
>  		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
> -		ad.a.u.net->family = sk->sk_family;
> +		ad.a.u.net->saddr.sa.sa_family = sk->sk_family;
> +		ad.a.u.net->daddr.sa.sa_family = sk->sk_family;
>  		ad.a.u.net->netif = skb->skb_iif;
>  		ipv4_skb_to_auditdata(skb, &ad.a, NULL);
>  #endif
> @@ -3384,7 +3384,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  
>  #ifdef CONFIG_AUDIT
>  	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
> -	ad.a.u.net->family = family;
> +	ad.a.u.net->saddr.sa.sa_family = family;
> +	ad.a.u.net->daddr.sa.sa_family = family;
>  	ad.a.u.net->netif = skb->skb_iif;
>  	ipv4_skb_to_auditdata(skb, &ad.a, NULL);
>  #endif


^ permalink raw reply

* [RFC 1/2] Use acked_out for reno-style ack acounting instead of sacked_out
From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans
In-Reply-To: <1376940568-16512-1-git-send-email-christoph.paasch@uclouvain.be>

This patch adds acked_out to tcp_sock, so that all acounting of acked
packets in case of non-sack connections is done within this field.

tcp_acked_out() sums up sacked_out and acked_out.

Tested-by: Benjamin Hesmans <benjamin.hesmans@uclouvain.be>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
---
 include/linux/tcp.h      |  1 +
 include/net/tcp.h        | 17 ++++++++++++-----
 net/ipv4/tcp_input.c     | 44 +++++++++++++++++++++++++++-----------------
 net/ipv4/tcp_minisocks.c |  1 +
 net/ipv4/tcp_output.c    |  2 +-
 net/ipv4/tcp_timer.c     |  2 +-
 6 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index d686334..6622595 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -241,6 +241,7 @@ struct tcp_sock {
 	u32	pushed_seq;	/* Last pushed seq, required to talk to windows */
 	u32	lost_out;	/* Lost packets			*/
 	u32	sacked_out;	/* SACK'd packets			*/
+	u32	acked_out;	/* DupACK'd packets			*/
 	u32	fackets_out;	/* FACK'd packets			*/
 	u32	tso_deferred;
 
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 09cb5c1..8210057 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -871,9 +871,14 @@ static inline void tcp_disable_early_retrans(struct tcp_sock *tp)
 	tp->do_early_retrans = 0;
 }
 
+static inline unsigned int tcp_acked_out(const struct tcp_sock *tp)
+{
+	return tp->sacked_out + tp->acked_out;
+}
+
 static inline unsigned int tcp_left_out(const struct tcp_sock *tp)
 {
-	return tp->sacked_out + tp->lost_out;
+	return tcp_acked_out(tp) + tp->lost_out;
 }
 
 /* This determines how many packets are "in the network" to the best
@@ -1446,12 +1451,12 @@ static inline void tcp_push_pending_frames(struct sock *sk)
 }
 
 /* Start sequence of the skb just after the highest skb with SACKed
- * bit, valid only if sacked_out > 0 or when the caller has ensured
+ * bit, valid only if sacked_out or acked_out > 0 or when the caller has ensured
  * validity by itself.
  */
 static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp)
 {
-	if (!tp->sacked_out)
+	if (!tp->sacked_out && !tp->acked_out)
 		return tp->snd_una;
 
 	if (tp->highest_sack == NULL)
@@ -1481,8 +1486,10 @@ static inline void tcp_highest_sack_combine(struct sock *sk,
 					    struct sk_buff *old,
 					    struct sk_buff *new)
 {
-	if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack))
-		tcp_sk(sk)->highest_sack = new;
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if ((tp->sacked_out || tp->acked_out) && (old == tp->highest_sack))
+		tp->highest_sack = new;
 }
 
 /* Determines whether this is a thin stream (which may suffer from
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e965cc7..af764d0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1748,8 +1748,8 @@ out:
 	return state.flag;
 }
 
-/* Limits sacked_out so that sum with lost_out isn't ever larger than
- * packets_out. Returns false if sacked_out adjustement wasn't necessary.
+/* Limits acked_out so that sum with lost_out isn't ever larger than
+ * packets_out. Returns false if acked_out adjustement wasn't necessary.
  */
 static bool tcp_limit_reno_sacked(struct tcp_sock *tp)
 {
@@ -1758,8 +1758,8 @@ static bool tcp_limit_reno_sacked(struct tcp_sock *tp)
 	holes = max(tp->lost_out, 1U);
 	holes = min(holes, tp->packets_out);
 
-	if ((tp->sacked_out + holes) > tp->packets_out) {
-		tp->sacked_out = tp->packets_out - holes;
+	if ((tp->acked_out + holes) > tp->packets_out) {
+		tp->acked_out = tp->packets_out - holes;
 		return true;
 	}
 	return false;
@@ -1781,7 +1781,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
 static void tcp_add_reno_sack(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	tp->sacked_out++;
+	tp->acked_out++;
 	tcp_check_reno_reordering(sk, 0);
 	tcp_verify_left_out(tp);
 }
@@ -1794,10 +1794,10 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked)
 
 	if (acked > 0) {
 		/* One ACK acked hole. The rest eat duplicate ACKs. */
-		if (acked - 1 >= tp->sacked_out)
-			tp->sacked_out = 0;
+		if (acked - 1 >= tp->acked_out)
+			tp->acked_out = 0;
 		else
-			tp->sacked_out -= acked - 1;
+			tp->acked_out -= acked - 1;
 	}
 	tcp_check_reno_reordering(sk, acked);
 	tcp_verify_left_out(tp);
@@ -1805,7 +1805,7 @@ static void tcp_remove_reno_sacks(struct sock *sk, int acked)
 
 static inline void tcp_reset_reno_sack(struct tcp_sock *tp)
 {
-	tp->sacked_out = 0;
+	tp->acked_out = 0;
 }
 
 static void tcp_clear_retrans_partial(struct tcp_sock *tp)
@@ -1823,6 +1823,7 @@ void tcp_clear_retrans(struct tcp_sock *tp)
 
 	tp->fackets_out = 0;
 	tp->sacked_out = 0;
+	tp->acked_out = 0;
 }
 
 /* Enter Loss state. If "how" is not zero, forget all SACK information
@@ -1857,6 +1858,7 @@ void tcp_enter_loss(struct sock *sk, int how)
 	tp->undo_marker = tp->snd_una;
 	if (how) {
 		tp->sacked_out = 0;
+		tp->acked_out = 0;
 		tp->fackets_out = 0;
 	}
 	tcp_clear_all_retrans_hints(tp);
@@ -1921,7 +1923,7 @@ static bool tcp_check_sack_reneging(struct sock *sk, int flag)
 
 static inline int tcp_fackets_out(const struct tcp_sock *tp)
 {
-	return tcp_is_reno(tp) ? tp->sacked_out + 1 : tp->fackets_out;
+	return tcp_is_reno(tp) ? tp->acked_out + 1 : tp->fackets_out;
 }
 
 /* Heurestics to calculate number of duplicate ACKs. There's no dupACKs
@@ -1941,7 +1943,7 @@ static inline int tcp_fackets_out(const struct tcp_sock *tp)
  */
 static inline int tcp_dupack_heuristics(const struct tcp_sock *tp)
 {
-	return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1;
+	return tcp_is_fack(tp) ? tp->fackets_out : tcp_acked_out(tp) + 1;
 }
 
 static bool tcp_pause_early_retransmit(struct sock *sk, int flag)
@@ -2077,7 +2079,7 @@ static bool tcp_time_to_recover(struct sock *sk, int flag)
 	 */
 	packets_out = tp->packets_out;
 	if (packets_out <= tp->reordering &&
-	    tp->sacked_out >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) &&
+	    tcp_acked_out(tp) >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) &&
 	    !tcp_may_send_now(sk)) {
 		/* We have nothing to send. This connection is limited
 		 * either by receiver window or by application.
@@ -2100,8 +2102,8 @@ static bool tcp_time_to_recover(struct sock *sk, int flag)
 	 * Mitigation A.3 in the RFC and delay the retransmission for a short
 	 * interval if appropriate.
 	 */
-	if (tp->do_early_retrans && !tp->retrans_out && tp->sacked_out &&
-	    (tp->packets_out >= (tp->sacked_out + 1) && tp->packets_out < 4) &&
+	if (tp->do_early_retrans && !tp->retrans_out && (tp->sacked_out || tp->acked_out) &&
+	    (tp->packets_out >= (tcp_acked_out(tp) + 1) && tp->packets_out < 4) &&
 	    !tcp_may_send_now(sk))
 		return !tcp_pause_early_retransmit(sk, flag);
 
@@ -2701,9 +2703,11 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
 				    (tcp_fackets_out(tp) > tp->reordering));
 	int fast_rexmit = 0;
 
-	if (WARN_ON(!tp->packets_out && tp->sacked_out))
+	if (WARN_ON(!tp->packets_out && (tp->sacked_out || tp->acked_out))) {
 		tp->sacked_out = 0;
-	if (WARN_ON(!tp->sacked_out && tp->fackets_out))
+		tp->acked_out = 0;
+	}
+	if (WARN_ON(!tp->sacked_out && !tp->acked_out && tp->fackets_out))
 		tp->fackets_out = 0;
 
 	/* Now state machine starts.
@@ -3078,6 +3082,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 
 #if FASTRETRANS_DEBUG > 0
 	WARN_ON((int)tp->sacked_out < 0);
+	WARN_ON((int)tp->acked_out < 0);
 	WARN_ON((int)tp->lost_out < 0);
 	WARN_ON((int)tp->retrans_out < 0);
 	if (!tp->packets_out && tcp_is_sack(tp)) {
@@ -3092,6 +3097,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 				 tp->sacked_out, icsk->icsk_ca_state);
 			tp->sacked_out = 0;
 		}
+		if (tp->acked_out) {
+			pr_debug("Leak a=%u %d\n",
+				 tp->acked_out, icsk->icsk_ca_state);
+			tp->acked_out = 0;
+		}
 		if (tp->retrans_out) {
 			pr_debug("Leak r=%u %d\n",
 				 tp->retrans_out, icsk->icsk_ca_state);
@@ -3270,7 +3280,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 	u32 prior_in_flight;
 	u32 prior_fackets;
 	int prior_packets = tp->packets_out;
-	const int prior_unsacked = tp->packets_out - tp->sacked_out;
+	const int prior_unsacked = tp->packets_out - tcp_acked_out(tp);
 	int acked = 0; /* Number of packets newly acked */
 	s32 sack_rtt = -1;
 
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 58a3e69..a2f5279 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -407,6 +407,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 		newtp->packets_out = 0;
 		newtp->retrans_out = 0;
 		newtp->sacked_out = 0;
+		newtp->acked_out = 0;
 		newtp->fackets_out = 0;
 		newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
 		tcp_enable_early_retrans(newtp);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 884efff..17ebbff 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1033,7 +1033,7 @@ static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int de
 
 	/* Reno case is special. Sigh... */
 	if (tcp_is_reno(tp) && decr > 0)
-		tp->sacked_out -= min_t(u32, tp->sacked_out, decr);
+		tp->acked_out -= min_t(u32, tp->acked_out, decr);
 
 	tcp_adjust_fackets_out(sk, skb, decr);
 
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 4b85e6f..82acaea 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -405,7 +405,7 @@ void tcp_retransmit_timer(struct sock *sk)
 		} else if (icsk->icsk_ca_state == TCP_CA_Loss) {
 			mib_idx = LINUX_MIB_TCPLOSSFAILURES;
 		} else if ((icsk->icsk_ca_state == TCP_CA_Disorder) ||
-			   tp->sacked_out) {
+			   tp->sacked_out || tp->acked_out) {
 			if (tcp_is_sack(tp))
 				mib_idx = LINUX_MIB_TCPSACKFAILURES;
 			else
-- 
1.8.1.2

^ permalink raw reply related

* [RFC 2/2] Account acked_out in sack, if the sack is invalid
From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans
In-Reply-To: <1376940568-16512-1-git-send-email-christoph.paasch@uclouvain.be>

In case of a sequence-number rewriting firewall (e.g., a Cisco Firewall:
https://supportforums.cisco.com/docs/DOC-12668#TCP_Sequence_Number_Randomization_and_SACK)
the SACK-blocks are not rewritten.
As we receive these ACK-packets, the sackblock is marked as invalid in
tcp_is_sackblock_valid(), and sacked_out will not be incremented.
Thus, fast-retransmit will not trigger and the stack will timeout after an
RTO. This completly kills the performance across this kind of firewalls.

This patch allows acked_out to increase, in case a sackblog is marked as
invalid. Further, it considers acked_out in the accounting when SACK has
been enabled on the connection.

Tested-by: Benjamin Hesmans <benjamin.hesmans@uclouvain.be>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
---
 net/ipv4/tcp_input.c  | 59 ++++++++++++++++++++++++++++++++++++++-------------
 net/ipv4/tcp_output.c |  4 ++--
 2 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index af764d0..ea99017 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -75,6 +75,8 @@
 #include <asm/unaligned.h>
 #include <net/netdma.h>
 
+static void tcp_add_reno_sack(struct sock *sk);
+
 int sysctl_tcp_timestamps __read_mostly = 1;
 int sysctl_tcp_window_scaling __read_mostly = 1;
 int sysctl_tcp_sack __read_mostly = 1;
@@ -1542,7 +1544,7 @@ static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_bl
 
 static int
 tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
-			u32 prior_snd_una, s32 *sack_rtt)
+			u32 prior_snd_una, s32 *sack_rtt, int flag)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	const unsigned char *ptr = (skb_transport_header(ack_skb) +
@@ -1554,7 +1556,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
 	struct sk_buff *skb;
 	int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3);
 	int used_sacks;
-	bool found_dup_sack = false;
+	bool found_dup_sack = false, first = true;
 	int i, j;
 	int first_sack_index;
 
@@ -1562,7 +1564,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
 	state.reord = tp->packets_out;
 	state.rtt = -1;
 
-	if (!tp->sacked_out) {
+	if (!tp->sacked_out && !tp->acked_out) {
 		if (WARN_ON(tp->fackets_out))
 			tp->fackets_out = 0;
 		tcp_highest_sack_reset(sk);
@@ -1612,6 +1614,29 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
 			NET_INC_STATS_BH(sock_net(sk), mib_idx);
 			if (i == 0)
 				first_sack_index = -1;
+
+			/* 1. Only account the dup-ack once.
+			 *
+			 * 2. If we are coming from tcp_ack, with an old_ack, we
+			 * should not increase acked_out, as the ack is old :)
+			 *
+			 * 3. Only increase acked_out, if this is really a
+			 * duplicate ack. Check is similar to the one in
+			 * tcp_ack, when setting is_dupack.
+			 *
+			 * 4. We have to reproduce the first check of
+			 * tcp_is_sackblock_valid, because we don't want to
+			 * account dup-acks if the sack-blog is corrupted.
+			 */
+			if (first &&
+			    !before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una) &&
+			    !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)) &&
+			    before(sp[used_sacks].start_seq, sp[used_sacks].end_seq)) {
+				first = false;
+				/* Disable FACK, as we can't trust SACKs anymore */
+				tcp_disable_fack(tp);
+				tcp_add_reno_sack(sk);
+			}
 			continue;
 		}
 
@@ -1740,6 +1765,7 @@ out:
 
 #if FASTRETRANS_DEBUG > 0
 	WARN_ON((int)tp->sacked_out < 0);
+	WARN_ON((int)tp->acked_out < 0);
 	WARN_ON((int)tp->lost_out < 0);
 	WARN_ON((int)tp->retrans_out < 0);
 	WARN_ON((int)tcp_packets_in_flight(tp) < 0);
@@ -1852,7 +1878,7 @@ void tcp_enter_loss(struct sock *sk, int how)
 
 	tcp_clear_retrans_partial(tp);
 
-	if (tcp_is_reno(tp))
+	if (tcp_is_reno(tp) || tp->acked_out)
 		tcp_reset_reno_sack(tp);
 
 	tp->undo_marker = tp->snd_una;
@@ -2189,7 +2215,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
 			lost = 1;
 		tcp_mark_head_lost(sk, lost, 0);
 	} else {
-		int sacked_upto = tp->sacked_out - tp->reordering;
+		int sacked_upto = tcp_acked_out(tp) - tp->reordering;
 		if (sacked_upto >= 0)
 			tcp_mark_head_lost(sk, sacked_upto, 0);
 		else if (fast_rexmit)
@@ -2551,7 +2577,7 @@ void tcp_simple_retransmit(struct sock *sk)
 	if (prior_lost == tp->lost_out)
 		return;
 
-	if (tcp_is_reno(tp))
+	if (tcp_is_reno(tp) || tp->acked_out)
 		tcp_limit_reno_sacked(tp);
 
 	tcp_verify_left_out(tp);
@@ -2634,11 +2660,11 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
 	}
 	if (flag & FLAG_DATA_ACKED)
 		icsk->icsk_retransmits = 0;
-	if (tcp_is_reno(tp)) {
+	if (tcp_is_reno(tp) || tp->acked_out) {
 		/* A Reno DUPACK means new data in F-RTO step 2.b above are
 		 * delivered. Lower inflight to clock out (re)tranmissions.
 		 */
-		if (after(tp->snd_nxt, tp->high_seq) && is_dupack)
+		if (tcp_is_reno(tp) && after(tp->snd_nxt, tp->high_seq) && is_dupack)
 			tcp_add_reno_sack(sk);
 		else if (flag & FLAG_SND_UNA_ADVANCED)
 			tcp_reset_reno_sack(tp);
@@ -2739,7 +2765,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
 			break;
 
 		case TCP_CA_Recovery:
-			if (tcp_is_reno(tp))
+			if (tcp_is_reno(tp) || tp->acked_out)
 				tcp_reset_reno_sack(tp);
 			if (tcp_try_undo_recovery(sk))
 				return;
@@ -2772,10 +2798,10 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
 			return;
 		/* Fall through to processing in Open state. */
 	default:
-		if (tcp_is_reno(tp)) {
+		if (tcp_is_reno(tp) || tp->acked_out) {
 			if (flag & FLAG_SND_UNA_ADVANCED)
 				tcp_reset_reno_sack(tp);
-			if (is_dupack)
+			if (is_dupack && tcp_is_reno(tp))
 				tcp_add_reno_sack(sk);
 		}
 
@@ -2952,7 +2978,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 	int flag = 0;
 	u32 pkts_acked = 0;
 	u32 reord = tp->packets_out;
-	u32 prior_sacked = tp->sacked_out;
+	u32 prior_sacked = tcp_acked_out(tp);
 	s32 seq_rtt = -1;
 	s32 ca_seq_rtt = -1;
 	ktime_t last_ackt = net_invalid_timestamp();
@@ -3050,12 +3076,15 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 		} else {
 			int delta;
 
+			if (tp->acked_out)
+				tcp_remove_reno_sacks(sk, pkts_acked);
+
 			/* Non-retransmitted hole got filled? That's reordering */
 			if (reord < prior_fackets)
 				tcp_update_reordering(sk, tp->fackets_out - reord, 0);
 
 			delta = tcp_is_fack(tp) ? pkts_acked :
-						  prior_sacked - tp->sacked_out;
+						  prior_sacked - tcp_acked_out(tp);
 			tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta);
 		}
 
@@ -3340,7 +3369,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
 		if (TCP_SKB_CB(skb)->sacked)
 			flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
-							&sack_rtt);
+							&sack_rtt, flag);
 
 		if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
 			flag |= FLAG_ECE;
@@ -3413,7 +3442,7 @@ old_ack:
 	 */
 	if (TCP_SKB_CB(skb)->sacked) {
 		flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
-						&sack_rtt);
+						&sack_rtt, flag);
 		tcp_fastretrans_alert(sk, acked, prior_unsacked,
 				      is_dupack, flag);
 	}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 17ebbff..2ecb943 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1008,7 +1008,7 @@ static void tcp_adjust_fackets_out(struct sock *sk, const struct sk_buff *skb,
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (!tp->sacked_out || tcp_is_reno(tp))
+	if ((!tp->sacked_out && !tp->acked_out) || tcp_is_reno(tp))
 		return;
 
 	if (after(tcp_highest_sack_seq(tp), TCP_SKB_CB(skb)->seq))
@@ -1032,7 +1032,7 @@ static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int de
 		tp->lost_out -= decr;
 
 	/* Reno case is special. Sigh... */
-	if (tcp_is_reno(tp) && decr > 0)
+	if ((tcp_is_reno(tp) || tp->acked_out) && decr > 0)
 		tp->acked_out -= min_t(u32, tp->acked_out, decr);
 
 	tcp_adjust_fackets_out(sk, skb, decr);
-- 
1.8.1.2

^ permalink raw reply related

* [RFC 0/2] Account for duplicate ACKs with invalid SACK-blocks
From: Christoph Paasch @ 2013-08-19 19:29 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, Phil Oester, Corey Hickey, Benjamin Hesmans
In-Reply-To: <1376935800.4226.71.camel@edumazet-glaptop>

There exist sequence-number rewriting middleboxes, who do not modify the 
sequence-number in the SACK-blocks.
Duplicate acknowledgments with these (invalid) SACK-blocks will not be
accounted in sacked_out, and thus no fast-retransmit will trigger.
So, the only way to recover from a packet-loss is through an RTO,
effectively killing the performance of TCP in this case.

Performance-results can be seen here:
http://tools.ietf.org/agenda/87/slides/slides-87-tcpm-11.pdf

Another solution might be to simply disable SACK, as soon as an invalid
SACK-block has been received (as suggested by Phil Oester). This however
might be too aggressive.

Christoph Paasch (2):
  Use acked_out for reno-style ack acounting instead of sacked_out
  Account acked_out in sack, if the sack is invalid

 include/linux/tcp.h      |   1 +
 include/net/tcp.h        |  17 +++++---
 net/ipv4/tcp_input.c     | 103 ++++++++++++++++++++++++++++++++---------------
 net/ipv4/tcp_minisocks.c |   1 +
 net/ipv4/tcp_output.c    |   6 +--
 net/ipv4/tcp_timer.c     |   2 +-
 6 files changed, 89 insertions(+), 41 deletions(-)

-- 
1.8.1.2

^ permalink raw reply

* Re: [PATCH] ipv6: handle Redirect ICMP Message with no Redirected Header option
From: Sergei Shtylyov @ 2013-08-19 19:00 UTC (permalink / raw)
  To: Duan Jiong; +Cc: davem, netdev
In-Reply-To: <5211F97B.4090209@cn.fujitsu.com>

Hello.

On 08/19/2013 02:54 PM, Duan Jiong wrote:

> From: Duan Jiong <duanj.fnst@cn.fujitsu.com>

> rfc 4861 says the Redirected Header option is optional, so
> the kernel should not drop the Redirect Message that has no
> Redirected Header option. In this patch, the function
> ip6_redirect_no_header() is introduced to deal with that
> condition.

> Signed-off-by: Duan Jiong <duanj.fnst@cn.fujitsu.com>
[...]

> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index b70f897..9934b87 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -1178,6 +1178,27 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
>   }
>   EXPORT_SYMBOL_GPL(ip6_redirect);
>   
> +void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, u32 mark)
> +{
> +	const struct ipv6hdr *iph = (struct ipv6hdr *) skb_network_header(skb);
> +	struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);

   Be consistent please: either put space after a typecast or not.

> +	struct dst_entry *dst;
> +	struct flowi6 fl6;

WBR, Sergei

^ permalink raw reply

* pull request: wireless 2013-08-19
From: John W. Linville @ 2013-08-19 18:59 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel

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

Dave,

This is a batch of fixes intended for the 3.11 stream...

Regarding the iwlwifi bits, Johannes says:

"We revert an rfkill bugfix that unfortunately caused more bugs, shuffle
some code to avoid touching the PCIe device before it's enabled and
disconnect if firmware fails to do our bidding. I also have Stanislaw's
fix to not crash in some channel switch scenarios."

As for the mac80211 bits, Johannes says:

"This time, I have one fix from Dan Carpenter for users of
nl80211hdr_put(), and one fix from myself fixing a regression with the
libertas driver."

Along with the above...

Dan Carpenter fixes some incorrectly placed "address of" operators
in hostap that caused copying of junk data.

Jussi Kivilinna corrects zd1201 to use an allocated buffer rather
than the stack for a URB operation.

Please let me know if there are problems!

Thanks,

John

---

The following changes since commit 0f7dd1aa8f959216f1faa71513b9d3c1a9065e5a:

  Merge tag 'clk-fixes-for-linus' of git://git.linaro.org/people/mturquette/linux (2013-08-16 10:00:18 -0700)

are available in the git repository at:


  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem

for you to fetch changes up to 22f0d2d1e7e76758f75887e616f2976323f85c26:

  Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless into for-davem (2013-08-19 14:24:45 -0400)

----------------------------------------------------------------

Dan Carpenter (2):
      Hostap: copying wrong data prism2_ioctl_giwaplist()
      nl80211: nl80211hdr_put() doesn't return an ERR_PTR

Emmanuel Grumbach (1):
      iwlwifi: pcie: disable L1 Active after pci_enable_device

Guy Cohen (1):
      Revert "iwlwifi: pcie: clear RFKILL interrupt in AMPG"

Johannes Berg (2):
      iwlwifi: mvm: disconnect if time event scheduling fails
      cfg80211: don't request disconnect if not connected

John W. Linville (3):
      Merge branch 'for-john' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes
      Merge branch 'for-john' of git://git.kernel.org/.../jberg/mac80211
      Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem

Jussi Kivilinna (1):
      zd1201: do not use stack as URB transfer_buffer

Stanislaw Gruszka (1):
      iwlwifi: dvm: fix calling ieee80211_chswitch_done() with NULL

 drivers/net/wireless/hostap/hostap_ioctl.c    |  4 ++--
 drivers/net/wireless/iwlwifi/dvm/mac80211.c   |  5 +++-
 drivers/net/wireless/iwlwifi/iwl-prph.h       |  2 --
 drivers/net/wireless/iwlwifi/mvm/time-event.c | 33 +++++++++++++++++++--------
 drivers/net/wireless/iwlwifi/pcie/rx.c        |  8 -------
 drivers/net/wireless/iwlwifi/pcie/trans.c     | 10 ++++----
 drivers/net/wireless/zd1201.c                 |  4 +++-
 net/wireless/nl80211.c                        | 22 +++++++++---------
 net/wireless/sme.c                            | 10 ++++----
 9 files changed, 52 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index ac07473..e509030 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -523,9 +523,9 @@ static int prism2_ioctl_giwaplist(struct net_device *dev,
 
 	data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
 
-	memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
+	memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
 	data->flags = 1; /* has quality information */
-	memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
+	memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
 	       sizeof(struct iw_quality) * data->length);
 
 	kfree(addr);
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 822f1a0..3193872 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1068,7 +1068,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+	if (!test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+		return;
+
+	if (ctx->vif)
 		ieee80211_chswitch_done(ctx->vif, is_success);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index a70c7b9..ff8cc75 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -97,8 +97,6 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS		(0x00000800)
 
-#define APMG_RTC_INT_STT_RFKILL		(0x10000000)
-
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index ad9bbca..7fd6fbf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -138,6 +138,20 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
 	schedule_work(&mvm->roc_done_wk);
 }
 
+static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					const char *errmsg)
+{
+	if (vif->type != NL80211_IFTYPE_STATION)
+		return false;
+	if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
+		return false;
+	if (errmsg)
+		IWL_ERR(mvm, "%s\n", errmsg);
+	ieee80211_connection_loss(vif);
+	return true;
+}
+
 /*
  * Handles a FW notification for an event that is known to the driver.
  *
@@ -163,8 +177,13 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
 	 * P2P Device discoveribility, while there are other higher priority
 	 * events in the system).
 	 */
-	WARN_ONCE(!le32_to_cpu(notif->status),
-		  "Failed to schedule time event\n");
+	if (WARN_ONCE(!le32_to_cpu(notif->status),
+		      "Failed to schedule time event\n")) {
+		if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) {
+			iwl_mvm_te_clear_data(mvm, te_data);
+			return;
+		}
+	}
 
 	if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
 		IWL_DEBUG_TE(mvm,
@@ -180,14 +199,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
 		 * By now, we should have finished association
 		 * and know the dtim period.
 		 */
-		if (te_data->vif->type == NL80211_IFTYPE_STATION &&
-		    (!te_data->vif->bss_conf.assoc ||
-		     !te_data->vif->bss_conf.dtim_period)) {
-			IWL_ERR(mvm,
-				"No assocation and the time event is over already...\n");
-			ieee80211_connection_loss(te_data->vif);
-		}
-
+		iwl_mvm_te_check_disconnect(mvm, te_data->vif,
+			"No assocation and the time event is over already...");
 		iwl_mvm_te_clear_data(mvm, te_data);
 	} else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
 		te_data->running = true;
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index f600e68..fd848cd 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -888,14 +888,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
 		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 		if (hw_rfkill) {
-			/*
-			 * Clear the interrupt in APMG if the NIC is going down.
-			 * Note that when the NIC exits RFkill (else branch), we
-			 * can't access prph and the NIC will be reset in
-			 * start_hw anyway.
-			 */
-			iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
-				       APMG_RTC_INT_STT_RFKILL);
 			set_bit(STATUS_RFKILL, &trans_pcie->status);
 			if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
 					       &trans_pcie->status))
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 96cfcdd..390e2f0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -1502,16 +1502,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 	spin_lock_init(&trans_pcie->reg_lock);
 	init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
-	/* W/A - seems to solve weird behavior. We need to remove this if we
-	 * don't want to stay in L1 all the time. This wastes a lot of power */
-	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
-			       PCIE_LINK_STATE_CLKPM);
-
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_no_pci;
 	}
 
+	/* W/A - seems to solve weird behavior. We need to remove this if we
+	 * don't want to stay in L1 all the time. This wastes a lot of power */
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+			       PCIE_LINK_STATE_CLKPM);
+
 	pci_set_master(pdev);
 
 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4941f20..b8ba1f9 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -98,10 +98,12 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw)
 		goto exit;
 
 	err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
-	    USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
+	    USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT);
 	if (err < 0)
 		goto exit;
 
+	memcpy(&ret, buf, sizeof(ret));
+
 	if (ret & 0x80) {
 		err = -EIO;
 		goto exit;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3fcba69..5f6e982 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2622,8 +2622,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_NEW_KEY);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -ENOBUFS;
 
 	cookie.msg = msg;
 	cookie.idx = key_idx;
@@ -6507,6 +6507,9 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
 					   NL80211_CMD_TESTMODE);
 		struct nlattr *tmdata;
 
+		if (!hdr)
+			break;
+
 		if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
 			genlmsg_cancel(skb, hdr);
 			break;
@@ -6951,9 +6954,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_REMAIN_ON_CHANNEL);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
@@ -7251,9 +7253,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
 		hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 				     NL80211_CMD_FRAME);
-
-		if (IS_ERR(hdr)) {
-			err = PTR_ERR(hdr);
+		if (!hdr) {
+			err = -ENOBUFS;
 			goto free_msg;
 		}
 	}
@@ -8132,9 +8133,8 @@ static int nl80211_probe_client(struct sk_buff *skb,
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_PROBE_CLIENT);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 81c8a10..20e86a9 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -976,21 +976,19 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, u16 reason, bool wextev)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
+	int err = 0;
 
 	ASSERT_WDEV_LOCK(wdev);
 
 	kfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
-	if (wdev->conn) {
+	if (wdev->conn)
 		err = cfg80211_sme_disconnect(wdev, reason);
-	} else if (!rdev->ops->disconnect) {
+	else if (!rdev->ops->disconnect)
 		cfg80211_mlme_down(rdev, dev);
-		err = 0;
-	} else {
+	else if (wdev->current_bss)
 		err = rdev_disconnect(rdev, dev, reason);
-	}
 
 	return err;
 }
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related

* Re: [PATCH] net: cpsw: Add support for wake-on-lan for cpsw
From: Sergei Shtylyov @ 2013-08-19 18:56 UTC (permalink / raw)
  To: ujhelyi.m; +Cc: davem, mugunthanvnm, netdev, linux-kernel
In-Reply-To: <1376907191-25491-1-git-send-email-ujhelyi.m@gmail.com>

Hello.

On 08/19/2013 02:13 PM, ujhelyi.m@gmail.com wrote:

> From: Matus Ujhelyi <ujhelyi.m@gmail.com>

> Signed-off-by: Matus Ujhelyi <ujhelyi.m@gmail.com>
> ---
>   drivers/net/ethernet/ti/cpsw.c |   25 +++++++++++++++++++++++++
>   1 file changed, 25 insertions(+)

> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
> index 22a7a43..f59302e 100644
> --- a/drivers/net/ethernet/ti/cpsw.c
> +++ b/drivers/net/ethernet/ti/cpsw.c
> @@ -1416,6 +1416,29 @@ static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
>   		return -EOPNOTSUPP;
>   }
>
> +static void
> +cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +	int slave_no = cpsw_slave_index(priv);

    Empty line wouldn't hurt here, after declaration.

> +	wol->supported = 0;
> +	wol->wolopts = 0;
> +	if (priv->slaves[slave_no].phy)
> +		phy_ethtool_get_wol(priv->slaves[slave_no].phy, wol);
> +
> +}
> +
> +static int
> +cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +	int slave_no = cpsw_slave_index(priv);

    Here too...

> +	if (priv->slaves[slave_no].phy)
> +		return phy_ethtool_set_wol(priv->slaves[slave_no].phy, wol);
> +	else
> +		return -EOPNOTSUPP;
> +}
> +
>   static const struct ethtool_ops cpsw_ethtool_ops = {
>   	.get_drvinfo	= cpsw_get_drvinfo,
>   	.get_msglevel	= cpsw_get_msglevel,

WBR, Sergei

^ permalink raw reply

* Re: 3.11-rc6 genetlink locking fix offends lockdep
From: Hugh Dickins @ 2013-08-19 18:52 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Ding Tianhong, Linus Torvalds, Greg KH, David S. Miller,
	Otcheretianski, Andrei, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, stable@vger.kernel.org, Pravin B Shelar,
	Thomas Graf
In-Reply-To: <1376911362.14734.11.camel@jlt4.sipsolutions.net>

On Mon, 19 Aug 2013, Johannes Berg wrote:
> On Mon, 2013-08-19 at 19:00 +0800, Ding Tianhong wrote:
> > On 2013/8/19 16:00, Johannes Berg wrote:
> > > 
> > >> 3.11-rc6's commit 58ad436fcf49 ("genetlink: fix family dump race")
> > >> gives me the lockdep trace below at startup.
> > > 
> > > Hmm. Yes, I see now how this happens, not sure why I didn't run into it.
> > > 
> > > The problem is that genl_family_rcv_msg() is called with the genl_lock
> > > held, and then calls netlink_dump_start() with it held, creating a
> > > genl_lock->cb_mutex dependency, but obviously the dump continuation is
> > > the other way around.
> > > 
> > > We could use the semaphore instead, I believe, but I don't really
> > > understand the mutex vs. semaphore well enough to be sure that's
> > > correct.
> > > 
> > > johannes
> > > 
> > it is useless, the logic need to modify or otherwise it will still call lockdep trace.
> 
> I don't believe so, the semaphore and cb_mutex don't have a dependency
> yet, afaict.

The down_read(&cb_lock) patch you suggested gives the lockdep trace below.

> 
> > maybe i could send a patch for it, if you wish.
> 
> What do you mean?
> 
> johannes

[    4.027797] e1000e 0000:00:19.0: irq 43 for MSI/MSI-X
[    4.129749] e1000e 0000:00:19.0: irq 43 for MSI/MSI-X
[    4.130179] IPv6: ADDRCONF(NETDEV_UP): eth1: link is not ready
[    4.134629] 
[    4.134646] ======================================================
[    4.134680] [ INFO: possible circular locking dependency detected ]
[    4.134714] 3.11.0-rc6 #3 Not tainted
[    4.134735] -------------------------------------------------------
[    4.134767] NetworkManager/357 is trying to acquire lock:
[    4.134797]  (cb_lock){++++++}, at: [<ffffffff8148204a>] ctrl_dumpfamily+0x38/0x108
[    4.134853] 
[    4.134853] but task is already holding lock:
[    4.134883]  (nlk->cb_mutex){+.+.+.}, at: [<ffffffff8147f148>] netlink_dump+0x1c/0x1d7
[    4.134938] 
[    4.134938] which lock already depends on the new lock.
[    4.134938] 
[    4.134981] 
[    4.134981] the existing dependency chain (in reverse order) is:
[    4.135020] 
[    4.135020] -> #2 (nlk->cb_mutex){+.+.+.}:
[    4.135056]        [<ffffffff810b34d2>] __lock_acquire+0x865/0x956
[    4.135094]        [<ffffffff810b39fc>] lock_acquire+0x57/0x6d
[    4.135129]        [<ffffffff81583e52>] mutex_lock_nested+0x5e/0x345
[    4.135167]        [<ffffffff81480122>] __netlink_dump_start+0xae/0x14e
[    4.135205]        [<ffffffff8148224b>] genl_rcv_msg+0xf4/0x252
[    4.135239]        [<ffffffff81481742>] netlink_rcv_skb+0x3e/0x8c
[    4.135275]        [<ffffffff8148199b>] genl_rcv+0x24/0x34
[    4.135307]        [<ffffffff814811ca>] netlink_unicast+0xed/0x17a
[    4.135342]        [<ffffffff814815d4>] netlink_sendmsg+0x2fb/0x345
[    4.135378]        [<ffffffff814503f7>] sock_sendmsg+0x79/0x8e
[    4.135412]        [<ffffffff81450707>] ___sys_sendmsg+0x231/0x2be
[    4.135448]        [<ffffffff81453228>] __sys_sendmsg+0x3d/0x5e
[    4.135483]        [<ffffffff81453256>] SyS_sendmsg+0xd/0x19
[    4.135517]        [<ffffffff81587c12>] system_call_fastpath+0x16/0x1b
[    4.135555] 
[    4.135555] -> #1 (genl_mutex){+.+.+.}:
[    4.135589]        [<ffffffff810b34d2>] __lock_acquire+0x865/0x956
[    4.135626]        [<ffffffff810b39fc>] lock_acquire+0x57/0x6d
[    4.135661]        [<ffffffff81583e52>] mutex_lock_nested+0x5e/0x345
[    4.135697]        [<ffffffff81482155>] genl_lock+0x12/0x14
[    4.135730]        [<ffffffff8148249d>] genl_lock_all+0x15/0x17
[    4.135763]        [<ffffffff81482b2a>] genl_register_family+0x51/0x142
[    4.135801]        [<ffffffff8148305f>] genl_register_family_with_ops+0x23/0x70
[    4.135842]        [<ffffffff8195e610>] genl_init+0x41/0x80
[    4.135876]        [<ffffffff81000267>] do_one_initcall+0x7f/0x108
[    4.135912]        [<ffffffff81930e29>] kernel_init_freeable+0x106/0x195
[    4.135951]        [<ffffffff81574621>] kernel_init+0x9/0xd1
[    4.135985]        [<ffffffff81587b6c>] ret_from_fork+0x7c/0xb0
[    4.136019] 
[    4.136019] -> #0 (cb_lock){++++++}:
[    4.136052]        [<ffffffff810b1fb0>] validate_chain.isra.21+0x836/0xe8e
[    4.136091]        [<ffffffff810b34d2>] __lock_acquire+0x865/0x956
[    4.136127]        [<ffffffff810b39fc>] lock_acquire+0x57/0x6d
[    4.136161]        [<ffffffff81584629>] down_read+0x42/0x57
[    4.136194]        [<ffffffff8148204a>] ctrl_dumpfamily+0x38/0x108
[    4.136230]        [<ffffffff8147f1b4>] netlink_dump+0x88/0x1d7
[    4.136264]        [<ffffffff8147f4b4>] netlink_recvmsg+0x1b1/0x2d1
[    4.137410]        [<ffffffff81450328>] sock_recvmsg+0x83/0x98
[    4.138459]        [<ffffffff814500c6>] ___sys_recvmsg+0x15d/0x207
[    4.139692]        [<ffffffff814533f7>] __sys_recvmsg+0x3d/0x5e
[    4.140918]        [<ffffffff81453425>] SyS_recvmsg+0xd/0x19
[    4.141975]        [<ffffffff81587c12>] system_call_fastpath+0x16/0x1b
[    4.143042] 
[    4.143042] other info that might help us debug this:
[    4.143042] 
[    4.146007] Chain exists of:
[    4.146007]   cb_lock --> genl_mutex --> nlk->cb_mutex
[    4.146007] 
[    4.148919]  Possible unsafe locking scenario:
[    4.148919] 
[    4.150955]        CPU0                    CPU1
[    4.152060]        ----                    ----
[    4.153030]   lock(nlk->cb_mutex);
[    4.153950]                                lock(genl_mutex);
[    4.154912]                                lock(nlk->cb_mutex);
[    4.155832]   lock(cb_lock);
[    4.156732] 
[    4.156732]  *** DEADLOCK ***
[    4.156732] 
[    4.159477] 1 lock held by NetworkManager/357:
[    4.160354]  #0:  (nlk->cb_mutex){+.+.+.}, at: [<ffffffff8147f148>] netlink_dump+0x1c/0x1d7
[    4.161411] 
[    4.161411] stack backtrace:
[    4.163489] CPU: 0 PID: 357 Comm: NetworkManager Not tainted 3.11.0-rc6 #3
[    4.164527] Hardware name: LENOVO 4174EH1/4174EH1, BIOS 8CET51WW (1.31 ) 11/29/2011
[    4.165491]  ffffffff81d0a450 ffff88022bd61938 ffffffff8157cf90 0000000000000006
[    4.166520]  ffffffff81cc85a0 ffff88022bd61988 ffffffff8157a8a8 ffff880200000001
[    4.167486]  ffff8802313ae080 ffff8802313ae080 ffff8802313ae750 ffff8802313ae080
[    4.168532] Call Trace:
[    4.169491]  [<ffffffff8157cf90>] dump_stack+0x4f/0x84
[    4.170532]  [<ffffffff8157a8a8>] print_circular_bug+0x2ad/0x2be
[    4.171507]  [<ffffffff810b1fb0>] validate_chain.isra.21+0x836/0xe8e
[    4.172548]  [<ffffffff810b34d2>] __lock_acquire+0x865/0x956
[    4.173525]  [<ffffffff810b39fc>] lock_acquire+0x57/0x6d
[    4.174536]  [<ffffffff8148204a>] ? ctrl_dumpfamily+0x38/0x108
[    4.175535]  [<ffffffff81584629>] down_read+0x42/0x57
[    4.176523]  [<ffffffff8148204a>] ? ctrl_dumpfamily+0x38/0x108
[    4.177564]  [<ffffffff8148204a>] ctrl_dumpfamily+0x38/0x108
[    4.178556]  [<ffffffff8145ac41>] ? __alloc_skb+0x97/0x1a0
[    4.179611]  [<ffffffff8147f1b4>] netlink_dump+0x88/0x1d7
[    4.180594]  [<ffffffff8147f4b4>] netlink_recvmsg+0x1b1/0x2d1
[    4.181645]  [<ffffffff81450328>] sock_recvmsg+0x83/0x98
[    4.182628]  [<ffffffff810f86fa>] ? might_fault+0x52/0xa2
[    4.183683]  [<ffffffff814500c6>] ___sys_recvmsg+0x15d/0x207
[    4.184668]  [<ffffffff810b34d2>] ? __lock_acquire+0x865/0x956
[    4.185731]  [<ffffffff81148b2b>] ? fget_light+0x35c/0x377
[    4.186707]  [<ffffffff81148933>] ? fget_light+0x164/0x377
[    4.187744]  [<ffffffff814533f7>] __sys_recvmsg+0x3d/0x5e
[    4.188709]  [<ffffffff8145471a>] ? sock_def_write_space+0x1b5/0x1b5
[    4.189755]  [<ffffffff81453425>] SyS_recvmsg+0xd/0x19
[    4.190729]  [<ffffffff81587c12>] system_call_fastpath+0x16/0x1b
[    4.192674] iwlwifi 0000:03:00.0: L1 Enabled; Disabling L0S
[    4.192887] iwlwifi 0000:03:00.0: Radio type=0x0-0x3-0x1

^ permalink raw reply

* Re: [PATCH net-next 2/3] net/mlx4_en: Notify user when TX ring in error state
From: Sergei Shtylyov @ 2013-08-19 18:49 UTC (permalink / raw)
  To: Amir Vadai; +Cc: David S. Miller, netdev
In-Reply-To: <1376894542-27854-3-git-send-email-amirv@mellanox.com>

Hello.

On 08/19/2013 10:42 AM, Amir Vadai wrote:

> When hardware gets into error state, must notify user about it.
> When QP in error state no traffic will be tx'ed from the attached
> tx_ring.

> Driver should know how to recover from this unexpected state. I will send later
> on the recovery flow, but having the print shouldn't be delayed.

> Signed-off-by: Amir Vadai <amirv@mellanox.com>
> ---
>   drivers/net/ethernet/mellanox/mlx4/en_tx.c | 8 ++++++++
>   1 file changed, 8 insertions(+)

> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> index 6dcca98..157bcd1 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> @@ -362,6 +362,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
>   		 */
>   		rmb();
>
> +		if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
> +			     MLX4_CQE_OPCODE_ERROR)) {
> +			struct mlx4_err_cqe *cqe_err = (struct mlx4_err_cqe *)cqe;

    Empty line wouldn't hurt here, after declaration.

> +			en_err(priv, "CQE error - vendor syndrom: 0x%x syndrom: 0x%x\n",

    s/syndrom/syndrome/ as below?

> +			       cqe_err->vendor_err_syndrome,
> +			       cqe_err->syndrome);
> +		}
> +

WBR, Sergei

^ permalink raw reply

* Re: [PATCH (net.git) 1/2] stmmac: disable at run-time the EEE if not supported
From: Sergei Shtylyov @ 2013-08-19 18:44 UTC (permalink / raw)
  To: Giuseppe CAVALLARO; +Cc: netdev
In-Reply-To: <1376894288-31279-1-git-send-email-peppe.cavallaro@st.com>

Hello.

On 08/19/2013 10:38 AM, Giuseppe CAVALLARO wrote:

> This patch is to disable the EEE (so HW and timers)
> for example when the phy communicates that the EEE
> can be supported nomore.

> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> ---
>   drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   24 ++++++++++++++++----
>   1 files changed, 19 insertions(+), 5 deletions(-)

> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 0a9bb9d..75cc2d3 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
[...]
> @@ -2166,7 +2181,6 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
>   static void stmmac_tx_timeout(struct net_device *dev)
>   {
>   	struct stmmac_priv *priv = netdev_priv(dev);
> -
>   	/* Clear Tx resources and restart transmitting again */

    Why? This seems unneeded change.

WBR, Sergei

^ permalink raw reply

* [PATCH net-next v7 8/8] openvswitch: Add vxlan tunneling support.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar, Jesse Gross

Following patch adds vxlan vport type for openvswitch using
vxlan api. So now there is vxlan dependency for openvswitch.

CC: Jesse Gross <jesse@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v2-v3:
 - Moved CONFIG_OPENVSWITCH_VXLAN check to makefile.
v1-v2:
 - removed NULL check in vxlan-rcv.
 - change vxlan-port create to look good.
 - Added Cisco copyright.
---
 include/uapi/linux/openvswitch.h |   11 ++
 net/openvswitch/Kconfig          |   13 +++
 net/openvswitch/Makefile         |    4 +
 net/openvswitch/vport-vxlan.c    |  204 ++++++++++++++++++++++++++++++++++++++
 net/openvswitch/vport.c          |    3 +
 net/openvswitch/vport.h          |    1 +
 6 files changed, 236 insertions(+), 0 deletions(-)
 create mode 100644 net/openvswitch/vport-vxlan.c

diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index c55efaa..52490b0 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -165,6 +165,7 @@ enum ovs_vport_type {
 	OVS_VPORT_TYPE_NETDEV,   /* network device */
 	OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
 	OVS_VPORT_TYPE_GRE,      /* GRE tunnel. */
+	OVS_VPORT_TYPE_VXLAN,	 /* VXLAN tunnel. */
 	__OVS_VPORT_TYPE_MAX
 };
 
@@ -211,6 +212,16 @@ enum ovs_vport_attr {
 
 #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
 
+/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
+ */
+enum {
+	OVS_TUNNEL_ATTR_UNSPEC,
+	OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
+	__OVS_TUNNEL_ATTR_MAX
+};
+
+#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1)
+
 /* Flows. */
 
 #define OVS_FLOW_FAMILY  "ovs_flow"
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig
index 27ee56b..bed30e6 100644
--- a/net/openvswitch/Kconfig
+++ b/net/openvswitch/Kconfig
@@ -40,3 +40,16 @@ config OPENVSWITCH_GRE
 	  Say N to exclude this support and reduce the binary size.
 
 	  If unsure, say Y.
+
+config OPENVSWITCH_VXLAN
+	bool "Open vSwitch VXLAN tunneling support"
+	depends on INET
+	depends on OPENVSWITCH
+	depends on VXLAN && !(OPENVSWITCH=y && VXLAN=m)
+	default y
+	---help---
+	  If you say Y here, then the Open vSwitch will be able create vxlan vport.
+
+	  Say N to exclude this support and reduce the binary size.
+
+	  If unsure, say Y.
diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile
index 01bddb2..82e4ee5 100644
--- a/net/openvswitch/Makefile
+++ b/net/openvswitch/Makefile
@@ -13,3 +13,7 @@ openvswitch-y := \
 	vport-gre.o \
 	vport-internal_dev.o \
 	vport-netdev.o
+
+ifneq ($(CONFIG_OPENVSWITCH_VXLAN),)
+openvswitch-y += vport-vxlan.o
+endif
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
new file mode 100644
index 0000000..36848bd
--- /dev/null
+++ b/net/openvswitch/vport-vxlan.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/net.h>
+#include <linux/rculist.h>
+#include <linux/udp.h>
+
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/ip_tunnels.h>
+#include <net/udp.h>
+#include <net/rtnetlink.h>
+#include <net/route.h>
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/vxlan.h>
+
+#include "datapath.h"
+#include "vport.h"
+
+/**
+ * struct vxlan_port - Keeps track of open UDP ports
+ * @vs: vxlan_sock created for the port.
+ * @name: vport name.
+ */
+struct vxlan_port {
+	struct vxlan_sock *vs;
+	char name[IFNAMSIZ];
+};
+
+static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
+{
+	return vport_priv(vport);
+}
+
+/* Called with rcu_read_lock and BH disabled. */
+static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni)
+{
+	struct ovs_key_ipv4_tunnel tun_key;
+	struct vport *vport = vs->data;
+	struct iphdr *iph;
+	__be64 key;
+
+	/* Save outer tunnel values */
+	iph = ip_hdr(skb);
+	key = cpu_to_be64(ntohl(vx_vni) >> 8);
+	ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY);
+
+	ovs_vport_receive(vport, skb, &tun_key);
+}
+
+static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
+{
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
+	__be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
+
+	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
+		return -EMSGSIZE;
+	return 0;
+}
+
+static void vxlan_tnl_destroy(struct vport *vport)
+{
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
+
+	vxlan_sock_release(vxlan_port->vs);
+
+	ovs_vport_deferred_free(vport);
+}
+
+static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
+{
+	struct net *net = ovs_dp_get_net(parms->dp);
+	struct nlattr *options = parms->options;
+	struct vxlan_port *vxlan_port;
+	struct vxlan_sock *vs;
+	struct vport *vport;
+	struct nlattr *a;
+	u16 dst_port;
+	int err;
+
+	if (!options) {
+		err = -EINVAL;
+		goto error;
+	}
+	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
+	if (a && nla_len(a) == sizeof(u16)) {
+		dst_port = nla_get_u16(a);
+	} else {
+		/* Require destination port from userspace. */
+		err = -EINVAL;
+		goto error;
+	}
+
+	vport = ovs_vport_alloc(sizeof(struct vxlan_port),
+				&ovs_vxlan_vport_ops, parms);
+	if (IS_ERR(vport))
+		return vport;
+
+	vxlan_port = vxlan_vport(vport);
+	strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
+
+	vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true);
+	if (IS_ERR(vs)) {
+		ovs_vport_free(vport);
+		return (void *)vs;
+	}
+	vxlan_port->vs = vs;
+
+	return vport;
+
+error:
+	return ERR_PTR(err);
+}
+
+static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
+{
+	struct net *net = ovs_dp_get_net(vport->dp);
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
+	__be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
+	struct rtable *rt;
+	struct flowi4 fl;
+	__be16 src_port;
+	int port_min;
+	int port_max;
+	__be16 df;
+	int err;
+
+	if (unlikely(!OVS_CB(skb)->tun_key)) {
+		err = -EINVAL;
+		goto error;
+	}
+
+	/* Route lookup */
+	memset(&fl, 0, sizeof(fl));
+	fl.daddr = OVS_CB(skb)->tun_key->ipv4_dst;
+	fl.saddr = OVS_CB(skb)->tun_key->ipv4_src;
+	fl.flowi4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos);
+	fl.flowi4_mark = skb->mark;
+	fl.flowi4_proto = IPPROTO_UDP;
+
+	rt = ip_route_output_key(net, &fl);
+	if (IS_ERR(rt)) {
+		err = PTR_ERR(rt);
+		goto error;
+	}
+
+	df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
+		htons(IP_DF) : 0;
+
+	skb->local_df = 1;
+
+	inet_get_local_port_range(&port_min, &port_max);
+	src_port = vxlan_src_port(port_min, port_max, skb);
+
+	err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb,
+			     fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst,
+			     OVS_CB(skb)->tun_key->ipv4_tos,
+			     OVS_CB(skb)->tun_key->ipv4_ttl, df,
+			     src_port, dst_port,
+			     htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8));
+	if (err < 0)
+		ip_rt_put(rt);
+error:
+	return err;
+}
+
+static const char *vxlan_get_name(const struct vport *vport)
+{
+	struct vxlan_port *vxlan_port = vxlan_vport(vport);
+	return vxlan_port->name;
+}
+
+const struct vport_ops ovs_vxlan_vport_ops = {
+	.type		= OVS_VPORT_TYPE_VXLAN,
+	.create		= vxlan_tnl_create,
+	.destroy	= vxlan_tnl_destroy,
+	.get_name	= vxlan_get_name,
+	.get_options	= vxlan_get_options,
+	.send		= vxlan_tnl_send,
+};
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index d4c7fa0..d69e0c0 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -42,6 +42,9 @@ static const struct vport_ops *vport_ops_list[] = {
 #ifdef CONFIG_OPENVSWITCH_GRE
 	&ovs_gre_vport_ops,
 #endif
+#ifdef CONFIG_OPENVSWITCH_VXLAN
+	&ovs_vxlan_vport_ops,
+#endif
 };
 
 /* Protected by RCU read lock for reading, ovs_mutex for writing. */
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index 376045c..1a9fbce 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -199,6 +199,7 @@ void ovs_vport_record_error(struct vport *, enum vport_err_type err_type);
 extern const struct vport_ops ovs_netdev_vport_ops;
 extern const struct vport_ops ovs_internal_vport_ops;
 extern const struct vport_ops ovs_gre_vport_ops;
+extern const struct vport_ops ovs_vxlan_vport_ops;
 
 static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
 				      const void *start, unsigned int len)
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 7/8] vxlan: Add tx-vlan offload support.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Following patch allows transmit side vlan offload for vxlan
devices.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v5-v6:
 - WARN_ON() style fix.
v2-v3:
 - Set NETIF_F_HW_VLAN_STAG_TX feature.
 - Added WARN on vlan tag push.
 - Fixed hw_features.
---
 drivers/net/vxlan.c |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 73e2557..b9401b5 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -27,6 +27,7 @@
 #include <linux/igmp.h>
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
+#include <linux/if_vlan.h>
 #include <linux/hash.h>
 #include <linux/ethtool.h>
 #include <net/arp.h>
@@ -1139,13 +1140,23 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
 	}
 
 	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
-			+ VXLAN_HLEN + sizeof(struct iphdr);
+			+ VXLAN_HLEN + sizeof(struct iphdr)
+			+ (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
 
 	/* Need space for new headers (invalidates iph ptr) */
 	err = skb_cow_head(skb, min_headroom);
 	if (unlikely(err))
 		return err;
 
+	if (vlan_tx_tag_present(skb)) {
+		if (WARN_ON(!__vlan_put_tag(skb,
+					    skb->vlan_proto,
+					    vlan_tx_tag_get(skb))))
+			return -ENOMEM;
+
+		skb->vlan_tci = 0;
+	}
+
 	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
 	vxh->vx_flags = htonl(VXLAN_FLAGS);
 	vxh->vx_vni = vni;
@@ -1560,8 +1571,11 @@ static void vxlan_setup(struct net_device *dev)
 	dev->features   |= NETIF_F_RXCSUM;
 	dev->features   |= NETIF_F_GSO_SOFTWARE;
 
+	dev->vlan_features = dev->features;
+	dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
 	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
 	dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+	dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
 	dev->priv_flags	&= ~IFF_XMIT_DST_RELEASE;
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 5/8] vxlan: Factor out vxlan send api.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Following patch allows more code sharing between vxlan and ovs-vxlan.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v1-v2:
 - revert back to original names.
---
 drivers/net/vxlan.c |   91 ++++++++++++++++++++++++++++++---------------------
 include/net/vxlan.h |    8 ++++
 2 files changed, 62 insertions(+), 37 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index aab927b..f3496e9 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1082,11 +1082,8 @@ static void vxlan_sock_put(struct sk_buff *skb)
 }
 
 /* On transmit, associate with the tunnel socket */
-static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
+static void vxlan_set_owner(struct sock *sk, struct sk_buff *skb)
 {
-	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct sock *sk = vxlan->vn_sock->sock->sk;
-
 	skb_orphan(skb);
 	sock_hold(sk);
 	skb->sk = sk;
@@ -1098,9 +1095,9 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
  *     better and maybe available from hardware
  *   secondary choice is to use jhash on the Ethernet header
  */
-static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
+__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb)
 {
-	unsigned int range = (vxlan->port_max - vxlan->port_min) + 1;
+	unsigned int range = (port_max - port_min) + 1;
 	u32 hash;
 
 	hash = skb_get_rxhash(skb);
@@ -1108,8 +1105,9 @@ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
 		hash = jhash(skb->data, 2 * ETH_ALEN,
 			     (__force u32) skb->protocol);
 
-	return htons((((u64) hash * range) >> 32) + vxlan->port_min);
+	return htons((((u64) hash * range) >> 32) + port_min);
 }
+EXPORT_SYMBOL_GPL(vxlan_src_port);
 
 static int handle_offloads(struct sk_buff *skb)
 {
@@ -1125,6 +1123,45 @@ static int handle_offloads(struct sk_buff *skb)
 	return 0;
 }
 
+int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
+		   struct rtable *rt, struct sk_buff *skb,
+		   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
+		   __be16 src_port, __be16 dst_port, __be32 vni)
+{
+	struct vxlanhdr *vxh;
+	struct udphdr *uh;
+	int err;
+
+	if (!skb->encapsulation) {
+		skb_reset_inner_headers(skb);
+		skb->encapsulation = 1;
+	}
+
+	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
+	vxh->vx_flags = htonl(VXLAN_FLAGS);
+	vxh->vx_vni = vni;
+
+	__skb_push(skb, sizeof(*uh));
+	skb_reset_transport_header(skb);
+	uh = udp_hdr(skb);
+
+	uh->dest = dst_port;
+	uh->source = src_port;
+
+	uh->len = htons(skb->len);
+	uh->check = 0;
+
+	vxlan_set_owner(vs->sock->sk, skb);
+
+	err = handle_offloads(skb);
+	if (err)
+		return err;
+
+	return iptunnel_xmit(net, rt, skb, src, dst,
+			IPPROTO_UDP, tos, ttl, df);
+}
+EXPORT_SYMBOL_GPL(vxlan_xmit_skb);
+
 /* Bypass encapsulation if the destination is local */
 static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
 			       struct vxlan_dev *dst_vxlan)
@@ -1162,8 +1199,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct rtable *rt;
 	const struct iphdr *old_iph;
-	struct vxlanhdr *vxh;
-	struct udphdr *uh;
 	struct flowi4 fl4;
 	__be32 dst;
 	__be16 src_port, dst_port;
@@ -1185,11 +1220,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		goto drop;
 	}
 
-	if (!skb->encapsulation) {
-		skb_reset_inner_headers(skb);
-		skb->encapsulation = 1;
-	}
-
 	/* Need space for new headers (invalidates iph ptr) */
 	if (skb_cow_head(skb, VXLAN_HEADROOM))
 		goto drop;
@@ -1204,7 +1234,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 	if (tos == 1)
 		tos = ip_tunnel_get_dsfield(old_iph, skb);
 
-	src_port = vxlan_src_port(vxlan, skb);
+	src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb);
 
 	memset(&fl4, 0, sizeof(fl4));
 	fl4.flowi4_oif = rdst->remote_ifindex;
@@ -1221,9 +1251,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 
 	if (rt->dst.dev == dev) {
 		netdev_dbg(dev, "circular route to %pI4\n", &dst);
-		ip_rt_put(rt);
 		dev->stats.collisions++;
-		goto tx_error;
+		goto rt_tx_error;
 	}
 
 	/* Bypass encapsulation if the destination is local */
@@ -1238,30 +1267,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		vxlan_encap_bypass(skb, vxlan, dst_vxlan);
 		return;
 	}
-	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
-	vxh->vx_flags = htonl(VXLAN_FLAGS);
-	vxh->vx_vni = htonl(vni << 8);
-
-	__skb_push(skb, sizeof(*uh));
-	skb_reset_transport_header(skb);
-	uh = udp_hdr(skb);
-
-	uh->dest = dst_port;
-	uh->source = src_port;
-
-	uh->len = htons(skb->len);
-	uh->check = 0;
-
-	vxlan_set_owner(dev, skb);
-
-	if (handle_offloads(skb))
-		goto drop;
 
 	tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
 	ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
 
-	err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, dst,
-			    IPPROTO_UDP, tos, ttl, df);
+	err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb,
+			     fl4.saddr, dst, tos, ttl, df,
+			     src_port, dst_port, htonl(vni << 8));
+
+	if (err < 0)
+		goto rt_tx_error;
 	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 
 	return;
@@ -1270,6 +1285,8 @@ drop:
 	dev->stats.tx_dropped++;
 	goto tx_free;
 
+rt_tx_error:
+	ip_rt_put(rt);
 tx_error:
 	dev->stats.tx_errors++;
 tx_free:
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 43de275..ad342e3 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -28,4 +28,12 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
 				  bool no_share);
 
 void vxlan_sock_release(struct vxlan_sock *vs);
+
+int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
+		   struct rtable *rt, struct sk_buff *skb,
+		   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
+		   __be16 src_port, __be16 dst_port, __be32 vni);
+
+__be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb);
+
 #endif
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 6/8] vxlan: Improve vxlan headroom calculation.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Rather than having static headroom calculation, adjust headroom
according to target device.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
 drivers/net/vxlan.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index f3496e9..73e2557 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1130,6 +1130,7 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
 {
 	struct vxlanhdr *vxh;
 	struct udphdr *uh;
+	int min_headroom;
 	int err;
 
 	if (!skb->encapsulation) {
@@ -1137,6 +1138,14 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
 		skb->encapsulation = 1;
 	}
 
+	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
+			+ VXLAN_HLEN + sizeof(struct iphdr);
+
+	/* Need space for new headers (invalidates iph ptr) */
+	err = skb_cow_head(skb, min_headroom);
+	if (unlikely(err))
+		return err;
+
 	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
 	vxh->vx_flags = htonl(VXLAN_FLAGS);
 	vxh->vx_vni = vni;
@@ -1220,10 +1229,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		goto drop;
 	}
 
-	/* Need space for new headers (invalidates iph ptr) */
-	if (skb_cow_head(skb, VXLAN_HEADROOM))
-		goto drop;
-
 	old_iph = ip_hdr(skb);
 
 	ttl = vxlan->ttl;
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 4/8] vxlan: Extend vxlan handlers for openvswitch.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Following patch adds data field to vxlan socket and export
vxlan handler api.
vh->data is required to store private data per vxlan handler.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
 drivers/net/vxlan.c |   45 +++++++++++++++++++--------------------------
 include/net/vxlan.h |   31 +++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 26 deletions(-)
 create mode 100644 include/net/vxlan.h

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 236c445..aab927b 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -41,6 +41,7 @@
 #include <net/inet_ecn.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <net/vxlan.h>
 
 #define VXLAN_VERSION	"0.1"
 
@@ -83,20 +84,6 @@ static int vxlan_net_id;
 
 static const u8 all_zeros_mac[ETH_ALEN];
 
-struct vxlan_sock;
-typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
-
-/* per UDP socket information */
-struct vxlan_sock {
-	vxlan_rcv_t	 *rcv;
-	struct hlist_node hlist;
-	struct rcu_head	  rcu;
-	struct work_struct del_work;
-	atomic_t	  refcnt;
-	struct socket	  *sock;
-	struct hlist_head vni_list[VNI_HASH_SIZE];
-};
-
 /* per-network namespace private data for this module */
 struct vxlan_net {
 	struct list_head  vxlan_list;
@@ -813,8 +800,10 @@ static void vxlan_sock_hold(struct vxlan_sock *vs)
 	atomic_inc(&vs->refcnt);
 }
 
-static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
+void vxlan_sock_release(struct vxlan_sock *vs)
 {
+	struct vxlan_net *vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
+
 	if (!atomic_dec_and_test(&vs->refcnt))
 		return;
 
@@ -824,6 +813,7 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
 
 	queue_work(vxlan_wq, &vs->del_work);
 }
+EXPORT_SYMBOL_GPL(vxlan_sock_release);
 
 /* Callback to update multicast group membership when first VNI on
  * multicast asddress is brought up
@@ -832,7 +822,6 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
 static void vxlan_igmp_join(struct work_struct *work)
 {
 	struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
-	struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
 	struct vxlan_sock *vs = vxlan->vn_sock;
 	struct sock *sk = vs->sock->sk;
 	struct ip_mreqn mreq = {
@@ -844,7 +833,7 @@ static void vxlan_igmp_join(struct work_struct *work)
 	ip_mc_join_group(sk, &mreq);
 	release_sock(sk);
 
-	vxlan_sock_release(vn, vs);
+	vxlan_sock_release(vs);
 	dev_put(vxlan->dev);
 }
 
@@ -852,7 +841,6 @@ static void vxlan_igmp_join(struct work_struct *work)
 static void vxlan_igmp_leave(struct work_struct *work)
 {
 	struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
-	struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
 	struct vxlan_sock *vs = vxlan->vn_sock;
 	struct sock *sk = vs->sock->sk;
 	struct ip_mreqn mreq = {
@@ -864,7 +852,7 @@ static void vxlan_igmp_leave(struct work_struct *work)
 	ip_mc_leave_group(sk, &mreq);
 	release_sock(sk);
 
-	vxlan_sock_release(vn, vs);
+	vxlan_sock_release(vs);
 	dev_put(vxlan->dev);
 }
 
@@ -1429,13 +1417,12 @@ static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan)
 static void vxlan_uninit(struct net_device *dev)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
 	struct vxlan_sock *vs = vxlan->vn_sock;
 
 	vxlan_fdb_delete_default(vxlan);
 
 	if (vs)
-		vxlan_sock_release(vn, vs);
+		vxlan_sock_release(vs);
 	free_percpu(dev->tstats);
 }
 
@@ -1653,7 +1640,7 @@ static void vxlan_del_work(struct work_struct *work)
 }
 
 static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
-					      vxlan_rcv_t *rcv)
+					      vxlan_rcv_t *rcv, void *data)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct vxlan_sock *vs;
@@ -1700,6 +1687,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
 	}
 	atomic_set(&vs->refcnt, 1);
 	vs->rcv = rcv;
+	vs->data = data;
 
 	/* Disable multicast loopback */
 	inet_sk(sk)->mc_loop = 0;
@@ -1714,16 +1702,20 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
 	return vs;
 }
 
-static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
-					 vxlan_rcv_t *rcv)
+struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
+				  vxlan_rcv_t *rcv, void *data,
+				  bool no_share)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct vxlan_sock *vs;
 
-	vs = vxlan_socket_create(net, port, rcv);
+	vs = vxlan_socket_create(net, port, rcv, data);
 	if (!IS_ERR(vs))
 		return vs;
 
+	if (no_share)	/* Return error if sharing is not allowed. */
+		return vs;
+
 	spin_lock(&vn->sock_lock);
 	vs = vxlan_find_sock(net, port);
 	if (vs) {
@@ -1739,6 +1731,7 @@ static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
 
 	return vs;
 }
+EXPORT_SYMBOL_GPL(vxlan_sock_add);
 
 /* Scheduled at device creation to bind to a socket */
 static void vxlan_sock_work(struct work_struct *work)
@@ -1749,7 +1742,7 @@ static void vxlan_sock_work(struct work_struct *work)
 	__be16 port = vxlan->dst_port;
 	struct vxlan_sock *nvs;
 
-	nvs = vxlan_sock_add(net, port, vxlan_rcv);
+	nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false);
 	spin_lock(&vn->sock_lock);
 	if (!IS_ERR(nvs))
 		vxlan_vs_add_dev(nvs, vxlan);
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
new file mode 100644
index 0000000..43de275
--- /dev/null
+++ b/include/net/vxlan.h
@@ -0,0 +1,31 @@
+#ifndef __NET_VXLAN_H
+#define __NET_VXLAN_H 1
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/udp.h>
+
+#define VNI_HASH_BITS	10
+#define VNI_HASH_SIZE	(1<<VNI_HASH_BITS)
+
+struct vxlan_sock;
+typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
+
+/* per UDP socket information */
+struct vxlan_sock {
+	struct hlist_node hlist;
+	vxlan_rcv_t	 *rcv;
+	void		 *data;
+	struct work_struct del_work;
+	struct socket	 *sock;
+	struct rcu_head	  rcu;
+	struct hlist_head vni_list[VNI_HASH_SIZE];
+	atomic_t	  refcnt;
+};
+
+struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
+				  vxlan_rcv_t *rcv, void *data,
+				  bool no_share);
+
+void vxlan_sock_release(struct vxlan_sock *vs);
+#endif
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 3/8] vxlan: Add vxlan recv demux.
From: Pravin B Shelar @ 2013-08-19 18:23 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Once we have ovs-vxlan functionality, one UDP port can be assigned
to kernel-vxlan or ovs-vxlan port.  Therefore following patch adds
vxlan demux functionality, so that vxlan or ovs module can
register for particular port.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v5-v6:
split from second patch from v5 patch series.
---
 drivers/net/vxlan.c |  103 +++++++++++++++++++++++++++++++++------------------
 1 files changed, 67 insertions(+), 36 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 1afb979..236c445 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -83,8 +83,12 @@ static int vxlan_net_id;
 
 static const u8 all_zeros_mac[ETH_ALEN];
 
+struct vxlan_sock;
+typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
+
 /* per UDP socket information */
 struct vxlan_sock {
+	vxlan_rcv_t	 *rcv;
 	struct hlist_node hlist;
 	struct rcu_head	  rcu;
 	struct work_struct del_work;
@@ -200,16 +204,10 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, __be16 port)
 	return NULL;
 }
 
-/* Look up VNI in a per net namespace table */
-static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port)
+static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)
 {
-	struct vxlan_sock *vs;
 	struct vxlan_dev *vxlan;
 
-	vs = vxlan_find_sock(net, port);
-	if (!vs)
-		return NULL;
-
 	hlist_for_each_entry_rcu(vxlan, vni_head(vs, id), hlist) {
 		if (vxlan->default_dst.remote_vni == id)
 			return vxlan;
@@ -218,6 +216,18 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port)
 	return NULL;
 }
 
+/* Look up VNI in a per net namespace table */
+static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port)
+{
+	struct vxlan_sock *vs;
+
+	vs = vxlan_find_sock(net, port);
+	if (!vs)
+		return NULL;
+
+	return vxlan_vs_find_vni(vs, id);
+}
+
 /* Fill in neighbour message in skbuff. */
 static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
 			  const struct vxlan_fdb *fdb,
@@ -861,13 +871,9 @@ static void vxlan_igmp_leave(struct work_struct *work)
 /* Callback from net/ipv4/udp.c to receive packets */
 static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-	struct iphdr *oip;
+	struct vxlan_sock *vs;
 	struct vxlanhdr *vxh;
-	struct vxlan_dev *vxlan;
-	struct pcpu_tstats *stats;
 	__be16 port;
-	__u32 vni;
-	int err;
 
 	/* Need Vxlan and inner Ethernet header to be present */
 	if (!pskb_may_pull(skb, VXLAN_HLEN))
@@ -882,24 +888,44 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		goto error;
 	}
 
-	/* Is this VNI defined? */
-	vni = ntohl(vxh->vx_vni) >> 8;
+	if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
+		goto drop;
+
 	port = inet_sk(sk)->inet_sport;
-	vxlan = vxlan_find_vni(sock_net(sk), vni, port);
-	if (!vxlan) {
-		netdev_dbg(skb->dev, "unknown vni %d port %u\n",
-			   vni, ntohs(port));
+
+	vs = vxlan_find_sock(sock_net(sk), port);
+	if (!vs)
 		goto drop;
-	}
 
-	if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) {
-		vxlan->dev->stats.rx_length_errors++;
-		vxlan->dev->stats.rx_errors++;
+	vs->rcv(vs, skb, vxh->vx_vni);
+	return 0;
+
+drop:
+	/* Consume bad packet */
+	kfree_skb(skb);
+	return 0;
+
+error:
+	/* Return non vxlan pkt */
+	return 1;
+}
+
+static void vxlan_rcv(struct vxlan_sock *vs,
+		      struct sk_buff *skb, __be32 vx_vni)
+{
+	struct iphdr *oip;
+	struct vxlan_dev *vxlan;
+	struct pcpu_tstats *stats;
+	__u32 vni;
+	int err;
+
+	vni = ntohl(vx_vni) >> 8;
+	/* Is this VNI defined? */
+	vxlan = vxlan_vs_find_vni(vs, vni);
+	if (!vxlan)
 		goto drop;
-	}
 
 	skb_reset_mac_header(skb);
-
 	skb->protocol = eth_type_trans(skb, vxlan->dev);
 
 	/* Ignore packet loops (and multicast echo) */
@@ -946,13 +972,10 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
 	netif_rx(skb);
 
-	return 0;
-error:
-	return 1;
+	return;
 drop:
 	/* Consume bad packet */
 	kfree_skb(skb);
-	return 0;
 }
 
 static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
@@ -1629,7 +1652,8 @@ static void vxlan_del_work(struct work_struct *work)
 	kfree_rcu(vs, rcu);
 }
 
-static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
+static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
+					      vxlan_rcv_t *rcv)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct vxlan_sock *vs;
@@ -1675,6 +1699,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
 		return ERR_PTR(rc);
 	}
 	atomic_set(&vs->refcnt, 1);
+	vs->rcv = rcv;
 
 	/* Disable multicast loopback */
 	inet_sk(sk)->mc_loop = 0;
@@ -1689,23 +1714,29 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
 	return vs;
 }
 
-static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port)
+static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
+					 vxlan_rcv_t *rcv)
 {
 	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct vxlan_sock *vs;
 
-	vs = vxlan_socket_create(net, port);
+	vs = vxlan_socket_create(net, port, rcv);
 	if (!IS_ERR(vs))
 		return vs;
 
 	spin_lock(&vn->sock_lock);
 	vs = vxlan_find_sock(net, port);
-	if (vs)
-		atomic_inc(&vs->refcnt);
-	else
+	if (vs) {
+		if (vs->rcv == rcv)
+			atomic_inc(&vs->refcnt);
+		else
+			vs = ERR_PTR(-EBUSY);
+	}
+	spin_unlock(&vn->sock_lock);
+
+	if (!vs)
 		vs = ERR_PTR(-EINVAL);
 
-	spin_unlock(&vn->sock_lock);
 	return vs;
 }
 
@@ -1718,7 +1749,7 @@ static void vxlan_sock_work(struct work_struct *work)
 	__be16 port = vxlan->dst_port;
 	struct vxlan_sock *nvs;
 
-	nvs = vxlan_sock_add(net, port);
+	nvs = vxlan_sock_add(net, port, vxlan_rcv);
 	spin_lock(&vn->sock_lock);
 	if (!IS_ERR(nvs))
 		vxlan_vs_add_dev(nvs, vxlan);
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v7 2/8] vxlan: Restructure vxlan receive.
From: Pravin B Shelar @ 2013-08-19 18:22 UTC (permalink / raw)
  To: netdev, davem; +Cc: stephen, Pravin B Shelar

Use iptunnel_pull_header() for better code sharing.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v5-v6:
split from second patch from v5 series.
---
 drivers/net/vxlan.c |   22 +++++++---------------
 1 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index b784ee6..1afb979 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -57,6 +57,7 @@
 #define VXLAN_VID_MASK	(VXLAN_N_VID - 1)
 /* IP header + UDP + VXLAN + Ethernet header */
 #define VXLAN_HEADROOM (20 + 8 + 8 + 14)
+#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 #define VXLAN_FLAGS 0x08000000	/* struct vxlanhdr.vx_flags required value. */
 
@@ -868,15 +869,12 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 	__u32 vni;
 	int err;
 
-	/* pop off outer UDP header */
-	__skb_pull(skb, sizeof(struct udphdr));
-
 	/* Need Vxlan and inner Ethernet header to be present */
-	if (!pskb_may_pull(skb, sizeof(struct vxlanhdr)))
+	if (!pskb_may_pull(skb, VXLAN_HLEN))
 		goto error;
 
-	/* Drop packets with reserved bits set */
-	vxh = (struct vxlanhdr *) skb->data;
+	/* Return packets with reserved bits set */
+	vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
 	if (vxh->vx_flags != htonl(VXLAN_FLAGS) ||
 	    (vxh->vx_vni & htonl(0xff))) {
 		netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
@@ -884,8 +882,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		goto error;
 	}
 
-	__skb_pull(skb, sizeof(struct vxlanhdr));
-
 	/* Is this VNI defined? */
 	vni = ntohl(vxh->vx_vni) >> 8;
 	port = inet_sk(sk)->inet_sport;
@@ -896,7 +892,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 		goto drop;
 	}
 
-	if (!pskb_may_pull(skb, ETH_HLEN)) {
+	if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) {
 		vxlan->dev->stats.rx_length_errors++;
 		vxlan->dev->stats.rx_errors++;
 		goto drop;
@@ -904,8 +900,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
 	skb_reset_mac_header(skb);
 
-	/* Re-examine inner Ethernet packet */
-	oip = ip_hdr(skb);
 	skb->protocol = eth_type_trans(skb, vxlan->dev);
 
 	/* Ignore packet loops (and multicast echo) */
@@ -913,11 +907,12 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 			       vxlan->dev->dev_addr) == 0)
 		goto drop;
 
+	/* Re-examine inner Ethernet packet */
+	oip = ip_hdr(skb);
 	if ((vxlan->flags & VXLAN_F_LEARN) &&
 	    vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source))
 		goto drop;
 
-	__skb_tunnel_rx(skb, vxlan->dev);
 	skb_reset_network_header(skb);
 
 	/* If the NIC driver gave us an encapsulated packet with
@@ -953,9 +948,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
 	return 0;
 error:
-	/* Put UDP header back */
-	__skb_push(skb, sizeof(struct udphdr));
-
 	return 1;
 drop:
 	/* Consume bad packet */
-- 
1.7.1

^ 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