Netdev List
 help / color / mirror / Atom feed
* PROBLEM: Regression - Can't upload some data in my network - Destination unreachable (Fragmentation needed)
From: Arthur Helfstein Fragoso @ 2014-11-24  4:51 UTC (permalink / raw)
  To: netdev; +Cc: davem

Hi all,

A few years ago, I was using Fedora 16 and I was unable to do any HTTP
POST at the place where I work. I also could not upload files via FTP,
send emails or do a 'git push'. So I tried Ubuntu 12.04 (or 12.10, I'm
not quite sure) and it worked perfectly.
Recently I updated it to 14.04 and the same problem I had in Fedora
came back.
I'm not an expert in understanding network packages, but by googling I
read that it could be that the network manager could have blocked the
ICMP MTU dicovery package. I could try to ask the network manager to
find a way to fix it, but I think more people could also have this
problem somewhere in the world.

I asked in Ubuntu's lauchpad, and Christopher M. Penalver guided me to
do a bisection.

I only have this problem at the place where I work and it happens with
any machine with a kernel older than 3.5. most use windows there and
they don't have this problem.

I did a bisection and I also have a wireshark output.

Those attachments are all in lauchpad.

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1349000

Recently there were some changes in the network, the bug stills
affects some upload services, like: git push, and sending messages in
pidgin...


Let me know what I could do or provide to help to fix this problem.




Bisection results:

3.5.0 is good

c0efc887dcadbdbfe171f028acfab9c7c00e9dde is good.

97bab73f987e2781129cd6f4b6379bf44d808cc6 - gives me a kernel panic
when trying to do an upload of data.

7b34ca2ac7063f4ebf07f85fd75253ed84d5c648 - same problem, kernel panic
when trying to do an upload of data.

The kernel panic goes up to 352e04b9111d608bd89ba7bd8070846d4f97d104

352e04b9111d608bd89ba7bd8070846d4f97d104 - doesn't give me a kernel
panic, but it just hangs when trying to upload data, and this is the
problem that I currently face in the upstream kernel.


to test what versions were good or bad, I tried to do an upload by
doing a 'git push' in a test repository. the bad versions just hanged
when I did 'git push'.



Thank you,

Arthur Helfstein Fragoso

^ permalink raw reply

* Re: [PATCH 07/17] new helpers: skb_copy_datagram_from_iter() and zerocopy_sg_from_iter()
From: Jason Wang @ 2014-11-24  5:34 UTC (permalink / raw)
  To: Ben Hutchings, Al Viro
  Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
	hch
In-Reply-To: <1416787365.7215.63.camel@decadent.org.uk>

On 11/24/2014 08:02 AM, Ben Hutchings wrote:
> On Sat, 2014-11-22 at 04:33 +0000, Al Viro wrote:
> [...]
>> --- a/net/core/datagram.c
>> +++ b/net/core/datagram.c
>> @@ -572,6 +572,77 @@ fault:
>>  }
>>  EXPORT_SYMBOL(skb_copy_datagram_from_iovec);
>>  
> Missing kernel-doc.
>
>> +int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
>> +				 struct iov_iter *from,
>> +				 int len)
>> +{
>> +	int start = skb_headlen(skb);
>> +	int i, copy = start - offset;
>> +	struct sk_buff *frag_iter;
>> +
>> +	/* Copy header. */
>> +	if (copy > 0) {
>> +		if (copy > len)
>> +			copy = len;
>> +		if (copy_from_iter(skb->data + offset, copy, from) != copy)
>> +			goto fault;
>> +		if ((len -= copy) == 0)
>> +			return 0;
>> +		offset += copy;
>> +	}
>> +
>> +	/* Copy paged appendix. Hmm... why does this look so complicated? */
>> +	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
>> +		int end;
>> +		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
>> +
>> +		WARN_ON(start > offset + len);
>> +
>> +		end = start + skb_frag_size(frag);
>> +		if ((copy = end - offset) > 0) {
>> +			size_t copied;
> Blank line needed after a declaration.
>
>> +			if (copy > len)
>> +				copy = len;
>> +			copied = copy_page_from_iter(skb_frag_page(frag),
>> +					  frag->page_offset + offset - start,
>> +					  copy, from);
>> +			if (copied != copy)
>> +				goto fault;
>> +
>> +			if (!(len -= copy))
>> +				return 0;
> The other two instances of this condition are written as:
>
> 			if ((len -= copy) == 0)
>
> Similarly in skb_copy_bits().
>
>> +			offset += copy;
>> +		}
>> +		start = end;
>> +	}
>> +
>> +	skb_walk_frags(skb, frag_iter) {
>> +		int end;
>> +
>> +		WARN_ON(start > offset + len);
>> +
>> +		end = start + frag_iter->len;
>> +		if ((copy = end - offset) > 0) {
>> +			if (copy > len)
>> +				copy = len;
>> +			if (skb_copy_datagram_from_iter(frag_iter,
>> +							offset - start,
>> +							from, copy))
>> +				goto fault;
>> +			if ((len -= copy) == 0)
>> +				return 0;
>> +			offset += copy;
>> +		}
>> +		start = end;
>> +	}
>> +	if (!len)
>> +		return 0;
>> +
>> +fault:
>> +	return -EFAULT;
>> +}
>> +EXPORT_SYMBOL(skb_copy_datagram_from_iter);
>> +
>>  /**
>>   *	zerocopy_sg_from_iovec - Build a zerocopy datagram from an iovec
>>   *	@skb: buffer to copy
>> @@ -643,6 +714,50 @@ int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
>>  }
>>  EXPORT_SYMBOL(zerocopy_sg_from_iovec);
>>  
> Missing kernel-doc.
>
>> +int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
>> +{
>> +	int len = iov_iter_count(from);
>> +	int copy = min_t(int, skb_headlen(skb), len);
>> +	int i = 0;
>> +
>> +	/* copy up to skb headlen */
>> +	if (skb_copy_datagram_from_iter(skb, 0, from, copy))
>> +		return -EFAULT;
>> +
>> +	while (iov_iter_count(from)) {
>> +		struct page *pages[MAX_SKB_FRAGS];
>> +		size_t start;
>> +		ssize_t copied;
>> +		unsigned long truesize;
>> +		int n = 0;
>> +
>> +		copied = iov_iter_get_pages(from, pages, ~0U, MAX_SKB_FRAGS, &start);
>> +		if (copied < 0)
>> +			return -EFAULT;
>> +
>> +		truesize = DIV_ROUND_UP(copied + start, PAGE_SIZE) * PAGE_SIZE;
> PAGE_ALIGN(copied + start) ?
>
>> +		skb->data_len += copied;
>> +		skb->len += copied;
>> +		skb->truesize += truesize;
>> +		atomic_add(truesize, &skb->sk->sk_wmem_alloc);
>> +		while (copied) {
>> +			int off = start;
> This variable seems redundant.  Can't we use start directly and move the
> 'start = 0' to the bottom of the loop?
>
>> +			int size = min_t(int, copied, PAGE_SIZE - off);
>> +			start = 0;
>> +			if (i < MAX_SKB_FRAGS)
>> +				skb_fill_page_desc(skb, i, pages[n], off, size);
>> +			else
>> +				put_page(pages[n]);
> Why is this condition needed, given we told iov_iter_get_pages() to
> limit to MAX_SKB_FRAGS pages?

We don't want to send truncated packets and there's no other way to put
those pages since it was not in the frag array.

^ permalink raw reply

* Re: [PATCH] net: introduce helper macra CMSG_FOREACH_HDR
From: David Miller @ 2014-11-24  5:55 UTC (permalink / raw)
  To: guz.fnst; +Cc: netdev, linux-kernel
In-Reply-To: <1416799125-13972-1-git-send-email-guz.fnst@cn.fujitsu.com>


Your postings do not make it to the mailing list, in fact they don't
even make it to the list server itself.

Generally speaking, sites in China have this problem off and on, and
in unpredictable ways.

You need to sort this out because I will not apply patches that don't
hit the mailing list for review.

^ permalink raw reply

* Re: [PATCH] net: introduce helper macra CMSG_FOREACH_HDR
From: Gu Zheng @ 2014-11-24  6:08 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-kernel
In-Reply-To: <20141124.005557.1508040983837292154.davem@davemloft.net>

Hi David,
On 11/24/2014 01:55 PM, David Miller wrote:

> 
> Your postings do not make it to the mailing list, in fact they don't
> even make it to the list server itself.

Thanks for your reminder.

> 
> Generally speaking, sites in China have this problem off and on, and
> in unpredictable ways.

Seems we should say thanks to GFW... 

> 
> You need to sort this out because I will not apply patches that don't
> hit the mailing list for review.

I'll confirm it first, and resent the patches once the problem is gone.

Regards,
Gu

> 

^ permalink raw reply

* [PATCH net-next v4] ipvlan: Initial check-in of the IPVLAN driver.
From: Mahesh Bandewar @ 2014-11-24  7:07 UTC (permalink / raw)
  To: netdev
  Cc: Eric Dumazet, Maciej Zenczykowski, Laurent Chavey, Tim Hockin,
	David Miller, Brandon Philips, Pavel Emelianov, Mahesh Bandewar

This driver is very similar to the macvlan driver except that it
uses L3 on the frame to determine the logical interface while
functioning as packet dispatcher. It inherits L2 of the master
device hence the packets on wire will have the same L2 for all
the packets originating from all virtual devices off of the same
master device.

This driver was developed keeping the namespace use-case in
mind. Hence most of the examples given here take that as the
base setup where main-device belongs to the default-ns and
virtual devices are assigned to the additional namespaces.

The device operates in two different modes and the difference
in these two modes in primarily in the TX side.

(a) L2 mode : In this mode, the device behaves as a L2 device.
TX processing upto L2 happens on the stack of the virtual device
associated with (namespace). Packets are switched after that
into the main device (default-ns) and queued for xmit.

RX processing is simple and all multicast, broadcast (if
applicable), and unicast belonging to the address(es) are
delivered to the virtual devices.

(b) L3 mode : In this mode, the device behaves like a L3 device.
TX processing upto L3 happens on the stack of the virtual device
associated with (namespace). Packets are switched to the
main-device (default-ns) for the L2 processing. Hence the routing
table of the default-ns will be used in this mode.

RX processins is somewhat similar to the L2 mode except that in
this mode only Unicast packets are delivered to the virtual device
while main-dev will handle all other packets.

The devices can be added using the "ip" command from the iproute2
package -

	ip link add link <master> <virtual> type ipvlan mode [ l2 | l3 ]

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Maciej Żenczykowski <maze@google.com>
Cc: Laurent Chavey <chavey@google.com>
Cc: Tim Hockin <thockin@google.com>
Cc: Brandon Philips <brandon.philips@coreos.com>
Cc: Pavel Emelianov <xemul@parallels.com>
---
 Documentation/networking/ipvlan.txt | 108 +++++
 drivers/net/Kconfig                 |  18 +
 drivers/net/Makefile                |   1 +
 drivers/net/ipvlan/Makefile         |   7 +
 drivers/net/ipvlan/ipvlan.h         | 130 ++++++
 drivers/net/ipvlan/ipvlan_core.c    | 607 +++++++++++++++++++++++++++
 drivers/net/ipvlan/ipvlan_main.c    | 789 ++++++++++++++++++++++++++++++++++++
 include/linux/netdevice.h           |   4 +
 include/uapi/linux/if_link.h        |  15 +
 9 files changed, 1679 insertions(+)
 create mode 100644 Documentation/networking/ipvlan.txt
 create mode 100644 drivers/net/ipvlan/Makefile
 create mode 100644 drivers/net/ipvlan/ipvlan.h
 create mode 100644 drivers/net/ipvlan/ipvlan_core.c
 create mode 100644 drivers/net/ipvlan/ipvlan_main.c

diff --git a/Documentation/networking/ipvlan.txt b/Documentation/networking/ipvlan.txt
new file mode 100644
index 000000000000..3f17bcb0ddc6
--- /dev/null
+++ b/Documentation/networking/ipvlan.txt
@@ -0,0 +1,108 @@
+
+                            IPVLAN Driver HOWTO
+
+Initial Release:
+	Mahesh Bandewar <maheshb AT google.com>
+
+1. Introduction:
+	This is conceptually very similar to the macvlan driver with one major
+exception of using L3 for mux-ing /demux-ing among slaves. This property makes
+the master device share the L2 with it's slave devices. I have developed this
+driver in conjuntion with network namespaces and not sure if there is use case
+outside of it.
+
+
+2. Building and Installation:
+	In order to build the driver, please select the config item CONFIG_IPVLAN.
+The driver can be built into the kernel (CONFIG_IPVLAN=y) or as a module
+(CONFIG_IPVLAN=m).
+
+
+3. Configuration:
+	There are no module parameters for this driver and it can be configured
+using IProute2/ip utility.
+
+	ip link add link <master-dev> <slave-dev> type ipvlan mode { l2 | L3 }
+
+	e.g. ip link add link ipvl0 eth0 type ipvlan mode l2
+
+
+4. Operating modes:
+	IPvlan has two modes of operation - L2 and L3. For a given master device,
+you can select one of these two modes and all slaves on that master will
+operate in the same (selected) mode. The RX mode is almost identical except
+that in L3 mode the slaves wont receive any multicast / broadcast traffic.
+L3 mode is more restrictive since routing is controlled from the other (mostly)
+default namespace.
+
+4.1 L2 mode:
+	In this mode TX processing happens on the stack instance attached to the
+slave device and packets are switched and queued to the master device to send
+out. In this mode the slaves will RX/TX multicast and broadcast (if applicable)
+as well.
+
+4.2 L3 mode:
+	In this mode TX processing upto L3 happens on the stack instance attached
+to the slave device and packets are switched to the stack instance of the
+master device for the L2 processing and routing from that instance will be
+used before packets are queued on the outbound device. In this mode the slaves
+will not receive nor can send multicast / broadcast traffic.
+
+
+5. What to choose (macvlan vs. ipvlan)?
+	These two devices are very similar in many regards and the specific use
+case could very well define which device to choose. if one of the following
+situations defines your use case then you can choose to use ipvlan -
+	(a) The Linux host that is connected to the external switch / router has
+policy configured that allows only one mac per port.
+	(b) No of virtual devices created on a master exceed the mac capacity and
+puts the NIC in promiscous mode and degraded performance is a concern.
+	(c) If the slave device is to be put into the hostile / untrusted network
+namespace where L2 on the slave could be changed / misused.
+
+
+6. Example configuration:
+
+  +=============================================================+
+  |  Host: host1                                                |
+  |                                                             |
+  |   +----------------------+      +----------------------+    |
+  |   |   NS:ns0             |      |  NS:ns1              |    |
+  |   |                      |      |                      |    |
+  |   |                      |      |                      |    |
+  |   |        ipvl0         |      |         ipvl1        |    |
+  |   +----------#-----------+      +-----------#----------+    |
+  |              #                              #               |
+  |              ################################               |
+  |                              # eth0                         |
+  +==============================#==============================+
+
+
+	(a) Create two network namespaces - ns0, ns1
+		ip netns add ns0
+		ip netns add ns1
+
+	(b) Create two ipvlan slaves on eth0 (master device)
+		ip link add link eth0 ipvl0 type ipvlan mode l2
+		ip link add link eth0 ipvl1 type ipvlan mode l2
+
+	(c) Assign slaves to the respective network namespaces
+		ip link set dev ipvl0 netns ns0
+		ip link set dev ipvl1 netns ns1
+
+	(d) Now switch to the namespace (ns0 or ns1) to configure the slave devices
+		- For ns0
+			(1) ip netns exec ns0 bash
+			(2) ip link set dev ipvl0 up
+			(3) ip link set dev lo up
+			(4) ip -4 addr add 127.0.0.1 dev lo
+			(5) ip -4 addr add $IPADDR dev ipvl0
+			(6) ip -4 route add default via $ROUTER dev ipvl0
+		- For ns1
+			(1) ip netns exec ns1 bash
+			(2) ip link set dev ipvl1 up
+			(3) ip link set dev lo up
+			(4) ip -4 addr add 127.0.0.1 dev lo
+			(5) ip -4 addr add $IPADDR dev ipvl1
+			(6) ip -4 route add default via $ROUTER dev ipvl1
+
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f9009be3f307..b6d64f546574 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -145,6 +145,24 @@ config MACVTAP
 	  To compile this driver as a module, choose M here: the module
 	  will be called macvtap.
 
+
+config IPVLAN
+    tristate "IP-VLAN support"
+    ---help---
+      This allows one to create virtual devices off of a main interface
+      and packets will be delivered based on the dest L3 (IPv6/IPv4 addr)
+      on packets. All interfaces (including the main interface) share L2
+      making it transparent to the connected L2 switch.
+
+      Ipvlan devices can be added using the "ip" command from the
+      iproute2 package starting with the iproute2-X.Y.ZZ release:
+
+      "ip link add link <main-dev> [ NAME ] type ipvlan"
+
+      To compile this driver as a module, choose M here: the module
+      will be called ipvlan.
+
+
 config VXLAN
        tristate "Virtual eXtensible Local Area Network (VXLAN)"
        depends on INET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 61aefdd1e173..e25fdd7d905e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,6 +6,7 @@
 # Networking Core Drivers
 #
 obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_IPVLAN) += ipvlan/
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_IFB) += ifb.o
diff --git a/drivers/net/ipvlan/Makefile b/drivers/net/ipvlan/Makefile
new file mode 100644
index 000000000000..df79910192d6
--- /dev/null
+++ b/drivers/net/ipvlan/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Ethernet Ipvlan driver
+#
+
+obj-$(CONFIG_IPVLAN) += ipvlan.o
+
+ipvlan-objs := ipvlan_core.o ipvlan_main.o
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
new file mode 100644
index 000000000000..ab3e7614ed71
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+#ifndef __IPVLAN_H
+#define __IPVLAN_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rculist.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_link.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/inetdevice.h>
+#include <net/rtnetlink.h>
+#include <net/gre.h>
+#include <net/route.h>
+#include <net/addrconf.h>
+
+#define IPVLAN_DRV	"ipvlan"
+#define IPV_DRV_VER	"0.1"
+
+#define IPVLAN_HASH_SIZE	(1 << BITS_PER_BYTE)
+#define IPVLAN_HASH_MASK	(IPVLAN_HASH_SIZE - 1)
+
+#define IPVLAN_MAC_FILTER_BITS	8
+#define IPVLAN_MAC_FILTER_SIZE	(1 << IPVLAN_MAC_FILTER_BITS)
+#define IPVLAN_MAC_FILTER_MASK	(IPVLAN_MAC_FILTER_SIZE - 1)
+
+typedef enum {
+	IPVL_IPV6 = 0,
+	IPVL_ICMPV6,
+	IPVL_IPV4,
+	IPVL_ARP,
+} ipvl_hdr_type;
+
+struct ipvl_pcpu_stats {
+	u64			rx_pkts;
+	u64			rx_bytes;
+	u64			rx_mcast;
+	u64			tx_pkts;
+	u64			tx_bytes;
+	struct u64_stats_sync	syncp;
+	u32			rx_errs;
+	u32			tx_drps;
+};
+
+struct ipvl_port;
+
+struct ipvl_dev {
+	struct net_device	*dev;
+	struct list_head	pnode;
+	struct ipvl_port	*port;
+	struct net_device	*phy_dev;
+	struct list_head	addrs;
+	int			ipv4cnt;
+	int			ipv6cnt;
+	struct ipvl_pcpu_stats	*pcpu_stats;
+	DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE);
+	netdev_features_t	sfeatures;
+	u32			msg_enable;
+	u16			mtu_adj;
+};
+
+struct ipvl_addr {
+	struct ipvl_dev		*master; /* Back pointer to master */
+	union {
+		struct in6_addr	ip6;	 /* IPv6 address on logical interface */
+		struct in_addr	ip4;	 /* IPv4 address on logical interface */
+	} ipu;
+#define ip6addr	ipu.ip6
+#define ip4addr ipu.ip4
+	struct hlist_node	hlnode;  /* Hash-table linkage */
+	struct list_head	anode;   /* logical-interface linkage */
+	struct rcu_head		rcu;
+	ipvl_hdr_type		atype;
+};
+
+struct ipvl_port {
+	struct net_device	*dev;
+	struct hlist_head	hlhead[IPVLAN_HASH_SIZE];
+	struct list_head	ipvlans;
+	struct rcu_head		rcu;
+	int			count;
+	u16			mode;
+};
+
+static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d)
+{
+	return rcu_dereference(d->rx_handler_data);
+}
+
+static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d)
+{
+	return rtnl_dereference(d->rx_handler_data);
+}
+
+static inline bool ipvlan_dev_master(struct net_device *d)
+{
+	return d->priv_flags & IFF_IPVLAN_MASTER;
+}
+
+static inline bool ipvlan_dev_slave(struct net_device *d)
+{
+	return d->priv_flags & IFF_IPVLAN_SLAVE;
+}
+
+void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev);
+void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval);
+void ipvlan_init_secret(void);
+unsigned int ipvlan_mac_hash(const unsigned char *addr);
+rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
+int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev);
+void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
+bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6);
+struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
+					const void *iaddr, bool is_v6);
+void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync);
+#endif /* __IPVLAN_H */
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
new file mode 100644
index 000000000000..a14d87783245
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -0,0 +1,607 @@
+/* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+
+#include "ipvlan.h"
+
+static u32 ipvlan_jhash_secret;
+
+void ipvlan_init_secret(void)
+{
+	net_get_random_once(&ipvlan_jhash_secret, sizeof(ipvlan_jhash_secret));
+}
+
+static void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
+			    unsigned int len, bool success, bool mcast)
+{
+	if (!ipvlan)
+		return;
+
+	if (likely(success)) {
+		struct ipvl_pcpu_stats *pcptr;
+
+		pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
+		u64_stats_update_begin(&pcptr->syncp);
+		pcptr->rx_pkts++;
+		pcptr->rx_bytes += len;
+		if (mcast)
+			pcptr->rx_mcast++;
+		u64_stats_update_end(&pcptr->syncp);
+	} else {
+		this_cpu_inc(ipvlan->pcpu_stats->rx_errs);
+	}
+}
+
+static u8 ipvlan_get_v6_hash(const void *iaddr)
+{
+	const struct in6_addr *ip6_addr = iaddr;
+
+	return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) &
+	       IPVLAN_HASH_MASK;
+}
+
+static u8 ipvlan_get_v4_hash(const void *iaddr)
+{
+	const struct in_addr *ip4_addr = iaddr;
+
+	return jhash_1word(ip4_addr->s_addr, ipvlan_jhash_secret) &
+	       IPVLAN_HASH_MASK;
+}
+
+struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
+					const void *iaddr, bool is_v6)
+{
+	struct ipvl_addr *addr;
+	u8 hash;
+
+	hash = is_v6 ? ipvlan_get_v6_hash(iaddr) :
+	       ipvlan_get_v4_hash(iaddr);
+	hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) {
+		if (is_v6 && addr->atype == IPVL_IPV6 &&
+		    ipv6_addr_equal(&addr->ip6addr, iaddr))
+			return addr;
+		else if (!is_v6 && addr->atype == IPVL_IPV4 &&
+			 addr->ip4addr.s_addr ==
+				((struct in_addr *)iaddr)->s_addr)
+			return addr;
+	}
+	return NULL;
+}
+
+void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
+{
+	struct ipvl_port *port = ipvlan->port;
+	u8 hash;
+
+	hash = (addr->atype == IPVL_IPV6) ?
+	       ipvlan_get_v6_hash(&addr->ip6addr) :
+	       ipvlan_get_v4_hash(&addr->ip4addr);
+	hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
+}
+
+void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
+{
+	hlist_del_rcu(&addr->hlnode);
+	if (sync)
+		synchronize_rcu();
+}
+
+bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
+{
+	struct ipvl_port *port = ipvlan->port;
+	struct ipvl_addr *addr;
+
+	list_for_each_entry(addr, &ipvlan->addrs, anode) {
+		if ((is_v6 && addr->atype == IPVL_IPV6 &&
+		    ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
+		    (!is_v6 && addr->atype == IPVL_IPV4 &&
+		    addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
+			return true;
+	}
+
+	if (ipvlan_ht_addr_lookup(port, iaddr, is_v6))
+		return true;
+
+	return false;
+}
+
+static void *ipvlan_get_L3_hdr(struct sk_buff *skb, int *type)
+{
+	void *lyr3h = NULL;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_ARP): {
+		struct arphdr *arph;
+
+		if (unlikely(!pskb_may_pull(skb, sizeof(*arph))))
+			return NULL;
+
+		arph = arp_hdr(skb);
+		*type = IPVL_ARP;
+		lyr3h = arph;
+		break;
+	}
+	case htons(ETH_P_IP): {
+		u32 pktlen;
+		struct iphdr *ip4h;
+
+		if (unlikely(!pskb_may_pull(skb, sizeof(*ip4h))))
+			return NULL;
+
+		ip4h = ip_hdr(skb);
+		pktlen = ntohs(ip4h->tot_len);
+		if (ip4h->ihl < 5 || ip4h->version != 4)
+			return NULL;
+		if (skb->len < pktlen || pktlen < (ip4h->ihl * 4))
+			return NULL;
+
+		*type = IPVL_IPV4;
+		lyr3h = ip4h;
+		break;
+	}
+	case htons(ETH_P_IPV6): {
+		struct ipv6hdr *ip6h;
+
+		if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h))))
+			return NULL;
+
+		ip6h = ipv6_hdr(skb);
+		if (ip6h->version != 6)
+			return NULL;
+
+		*type = IPVL_IPV6;
+		lyr3h = ip6h;
+		/* Only Neighbour Solicitation pkts need different treatment */
+		if (ipv6_addr_any(&ip6h->saddr) &&
+		    ip6h->nexthdr == NEXTHDR_ICMP) {
+			*type = IPVL_ICMPV6;
+			lyr3h = ip6h + 1;
+		}
+		break;
+	}
+	default:
+		return NULL;
+	}
+
+	return lyr3h;
+}
+
+unsigned int ipvlan_mac_hash(const unsigned char *addr)
+{
+	u32 hash = jhash_1word(__get_unaligned_cpu32(addr+2),
+			       ipvlan_jhash_secret);
+
+	return hash & IPVLAN_MAC_FILTER_MASK;
+}
+
+static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb,
+				   const struct ipvl_dev *in_dev, bool local)
+{
+	struct ethhdr *eth = eth_hdr(skb);
+	struct ipvl_dev *ipvlan;
+	struct sk_buff *nskb;
+	unsigned int len;
+	unsigned int mac_hash;
+	int ret;
+
+	if (skb->protocol == htons(ETH_P_PAUSE))
+		return;
+
+	list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+		if (local && (ipvlan == in_dev))
+			continue;
+
+		mac_hash = ipvlan_mac_hash(eth->h_dest);
+		if (!test_bit(mac_hash, ipvlan->mac_filters))
+			continue;
+
+		ret = NET_RX_DROP;
+		len = skb->len + ETH_HLEN;
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (!nskb)
+			goto mcast_acct;
+
+		if (ether_addr_equal(eth->h_dest, ipvlan->phy_dev->broadcast))
+			nskb->pkt_type = PACKET_BROADCAST;
+		else
+			nskb->pkt_type = PACKET_MULTICAST;
+
+		nskb->dev = ipvlan->dev;
+		if (local)
+			ret = dev_forward_skb(ipvlan->dev, nskb);
+		else
+			ret = netif_rx(nskb);
+mcast_acct:
+		ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
+	}
+
+	/* Locally generated? ...Forward a copy to the main-device as
+	 * well. On the RX side we'll ignore it (wont give it to any
+	 * of the virtual devices.
+	 */
+	if (local) {
+		nskb = skb_clone(skb, GFP_ATOMIC);
+		if (nskb) {
+			if (ether_addr_equal(eth->h_dest, port->dev->broadcast))
+				nskb->pkt_type = PACKET_BROADCAST;
+			else
+				nskb->pkt_type = PACKET_MULTICAST;
+
+			dev_forward_skb(port->dev, nskb);
+		}
+	}
+}
+
+static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
+			    bool local)
+{
+	struct ipvl_dev *ipvlan = addr->master;
+	struct net_device *dev = ipvlan->dev;
+	unsigned int len;
+	rx_handler_result_t ret = RX_HANDLER_CONSUMED;
+	bool success = false;
+
+	len = skb->len + ETH_HLEN;
+	if (unlikely(!(dev->flags & IFF_UP))) {
+		kfree_skb(skb);
+		goto out;
+	}
+
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		goto out;
+
+	skb->dev = dev;
+	skb->pkt_type = PACKET_HOST;
+
+	if (local) {
+		if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS)
+			success = true;
+	} else {
+		ret = RX_HANDLER_ANOTHER;
+		success = true;
+	}
+
+out:
+	ipvlan_count_rx(ipvlan, len, success, false);
+	return ret;
+}
+
+static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
+					    void *lyr3h, int addr_type,
+					    bool use_dest)
+{
+	struct ipvl_addr *addr = NULL;
+
+	if (addr_type == IPVL_IPV6) {
+		struct ipv6hdr *ip6h;
+		struct in6_addr *i6addr;
+
+		ip6h = (struct ipv6hdr *)lyr3h;
+		i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
+		addr = ipvlan_ht_addr_lookup(port, i6addr, true);
+	} else if (addr_type == IPVL_ICMPV6) {
+		struct nd_msg *ndmh;
+		struct in6_addr *i6addr;
+
+		/* Make sure that the NeighborSolicitation ICMPv6 packets
+		 * are handled to avoid DAD issue.
+		 */
+		ndmh = (struct nd_msg *)lyr3h;
+		if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+			i6addr = &ndmh->target;
+			addr = ipvlan_ht_addr_lookup(port, i6addr, true);
+		}
+	} else if (addr_type == IPVL_IPV4) {
+		struct iphdr *ip4h;
+		__be32 *i4addr;
+
+		ip4h = (struct iphdr *)lyr3h;
+		i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
+		addr = ipvlan_ht_addr_lookup(port, i4addr, false);
+	} else if (addr_type == IPVL_ARP) {
+		struct arphdr *arph;
+		unsigned char *arp_ptr;
+		__be32 dip;
+
+		arph = (struct arphdr *)lyr3h;
+		arp_ptr = (unsigned char *)(arph + 1);
+		if (use_dest)
+			arp_ptr += (2 * port->dev->addr_len) + 4;
+		else
+			arp_ptr += port->dev->addr_len;
+
+		memcpy(&dip, arp_ptr, 4);
+		addr = ipvlan_ht_addr_lookup(port, &dip, false);
+	}
+
+	return addr;
+}
+
+static int ipvlan_process_v4_outbound(struct sk_buff *skb)
+{
+	const struct iphdr *ip4h = ip_hdr(skb);
+	struct net_device *dev = skb->dev;
+	struct rtable *rt;
+	int err, ret = NET_XMIT_DROP;
+	struct flowi4 fl4 = {
+		.flowi4_oif = dev->iflink,
+		.flowi4_tos = RT_TOS(ip4h->tos),
+		.flowi4_flags = FLOWI_FLAG_ANYSRC,
+		.daddr = ip4h->daddr,
+		.saddr = ip4h->saddr,
+	};
+
+	rt = ip_route_output_flow(dev_net(dev), &fl4, NULL);
+	if (IS_ERR(rt))
+		goto err;
+
+	if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
+		ip_rt_put(rt);
+		goto err;
+	}
+	skb_dst_drop(skb);
+	skb_dst_set(skb, &rt->dst);
+	err = ip_local_out(skb);
+	if (unlikely(net_xmit_eval(err)))
+		dev->stats.tx_errors++;
+	else
+		ret = NET_XMIT_SUCCESS;
+	goto out;
+err:
+	dev->stats.tx_errors++;
+	kfree_skb(skb);
+out:
+	return ret;
+}
+
+static int ipvlan_process_v6_outbound(struct sk_buff *skb)
+{
+	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct net_device *dev = skb->dev;
+	struct dst_entry *dst;
+	int err, ret = NET_XMIT_DROP;
+	struct flowi6 fl6 = {
+		.flowi6_iif = skb->dev->ifindex,
+		.daddr = ip6h->daddr,
+		.saddr = ip6h->saddr,
+		.flowi6_flags = FLOWI_FLAG_ANYSRC,
+		.flowlabel = ip6_flowinfo(ip6h),
+		.flowi6_mark = skb->mark,
+		.flowi6_proto = ip6h->nexthdr,
+	};
+
+	dst = ip6_route_output(dev_net(dev), NULL, &fl6);
+	if (IS_ERR(dst))
+		goto err;
+
+	skb_dst_drop(skb);
+	skb_dst_set(skb, dst);
+	err = ip6_local_out(skb);
+	if (unlikely(net_xmit_eval(err)))
+		dev->stats.tx_errors++;
+	else
+		ret = NET_XMIT_SUCCESS;
+	goto out;
+err:
+	dev->stats.tx_errors++;
+	kfree_skb(skb);
+out:
+	return ret;
+}
+
+static int ipvlan_process_outbound(struct sk_buff *skb,
+				   const struct ipvl_dev *ipvlan)
+{
+	struct ethhdr *ethh = eth_hdr(skb);
+	int ret = NET_XMIT_DROP;
+
+	/* In this mode we dont care about multicast and broadcast traffic */
+	if (is_multicast_ether_addr(ethh->h_dest)) {
+		pr_warn_ratelimited("Dropped {multi|broad}cast of type= [%x]\n",
+				    ntohs(skb->protocol));
+		kfree_skb(skb);
+		goto out;
+	}
+
+	/* The ipvlan is a pseudo-L2 device, so the packets that we receive
+	 * will have L2; which need to discarded and processed further
+	 * in the net-ns of the main-device.
+	 */
+	if (skb_mac_header_was_set(skb)) {
+		skb_pull(skb, sizeof(*ethh));
+		skb->mac_header = (typeof(skb->mac_header))~0U;
+		skb_reset_network_header(skb);
+	}
+
+	if (skb->protocol == htons(ETH_P_IPV6))
+		ret = ipvlan_process_v6_outbound(skb);
+	else if (skb->protocol == htons(ETH_P_IP))
+		ret = ipvlan_process_v4_outbound(skb);
+	else {
+		pr_warn_ratelimited("Dropped outbound packet type=%x\n",
+				    ntohs(skb->protocol));
+		kfree_skb(skb);
+	}
+out:
+	return ret;
+}
+
+static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+	void *lyr3h;
+	struct ipvl_addr *addr;
+	int addr_type;
+
+	lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
+	if (!lyr3h)
+		goto out;
+
+	addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
+	if (addr)
+		return ipvlan_rcv_frame(addr, skb, true);
+
+out:
+	skb->dev = ipvlan->phy_dev;
+	return ipvlan_process_outbound(skb, ipvlan);
+}
+
+static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ethhdr *eth = eth_hdr(skb);
+	struct ipvl_addr *addr;
+	void *lyr3h;
+	int addr_type;
+
+	if (ether_addr_equal(eth->h_dest, eth->h_source)) {
+		lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
+		if (lyr3h) {
+			addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
+			if (addr)
+				return ipvlan_rcv_frame(addr, skb, true);
+		}
+		skb = skb_share_check(skb, GFP_ATOMIC);
+		if (!skb)
+			return NET_XMIT_DROP;
+
+		/* Packet definitely does not belong to any of the
+		 * virtual devices, but the dest is local. So forward
+		 * the skb for the main-dev. At the RX side we just return
+		 * RX_PASS for it to be processed further on the stack.
+		 */
+		return dev_forward_skb(ipvlan->phy_dev, skb);
+
+	} else if (is_multicast_ether_addr(eth->h_dest)) {
+		u8 ip_summed = skb->ip_summed;
+
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		ipvlan_multicast_frame(ipvlan->port, skb, ipvlan, true);
+		skb->ip_summed = ip_summed;
+	}
+
+	skb->dev = ipvlan->phy_dev;
+	return dev_queue_xmit(skb);
+}
+
+int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_port *port = ipvlan_port_get_rcu(ipvlan->phy_dev);
+
+	if (!port)
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
+		goto out;
+
+	switch(port->mode) {
+	case IPVLAN_MODE_L2:
+		return ipvlan_xmit_mode_l2(skb, dev);
+	case IPVLAN_MODE_L3:
+		return ipvlan_xmit_mode_l3(skb, dev);
+	}
+
+	/* Should not reach here */
+	WARN_ONCE(true, "ipvlan_queue_xmit() called for mode = [%hx]\n",
+			  port->mode);
+out:
+	kfree_skb(skb);
+	return NET_XMIT_DROP;
+}
+
+static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port)
+{
+	struct ethhdr *eth = eth_hdr(skb);
+	struct ipvl_addr *addr;
+	void *lyr3h;
+	int addr_type;
+
+	if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) {
+		lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
+		if (!lyr3h)
+			return true;
+
+		addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false);
+		if (addr)
+			return false;
+	}
+
+	return true;
+}
+
+static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
+						 struct ipvl_port *port)
+{
+	void *lyr3h;
+	int addr_type;
+	struct ipvl_addr *addr;
+	struct sk_buff *skb = *pskb;
+	rx_handler_result_t ret = RX_HANDLER_PASS;
+
+	lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
+	if (!lyr3h)
+		goto out;
+
+	addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
+	if (addr)
+		ret = ipvlan_rcv_frame(addr, skb, false);
+
+out:
+	return ret;
+}
+
+static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
+						 struct ipvl_port *port)
+{
+	struct sk_buff *skb = *pskb;
+	struct ethhdr *eth = eth_hdr(skb);
+	rx_handler_result_t ret = RX_HANDLER_PASS;
+	void *lyr3h;
+	int addr_type;
+
+	if (is_multicast_ether_addr(eth->h_dest)) {
+		if (ipvlan_external_frame(skb, port))
+			ipvlan_multicast_frame(port, skb, NULL, false);
+	} else {
+		struct ipvl_addr *addr;
+
+		lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
+		if (!lyr3h)
+			return ret;
+
+		addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
+		if (addr)
+			ret = ipvlan_rcv_frame(addr, skb, false);
+	}
+
+	return ret;
+}
+
+rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
+{
+	struct sk_buff *skb = *pskb;
+	struct ipvl_port *port = ipvlan_port_get_rcu(skb->dev);
+
+	if (!port)
+		return RX_HANDLER_PASS;
+
+	switch (port->mode) {
+	case IPVLAN_MODE_L2:
+		return ipvlan_handle_mode_l2(pskb, port);
+	case IPVLAN_MODE_L3:
+		return ipvlan_handle_mode_l3(pskb, port);
+	}
+
+	/* Should not reach here */
+	WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n",
+			  port->mode);
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
new file mode 100644
index 000000000000..c3df84bd2857
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -0,0 +1,789 @@
+/* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+
+#include "ipvlan.h"
+
+void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
+{
+	ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj;
+}
+
+void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval)
+{
+	struct ipvl_dev *ipvlan;
+
+	if (port->mode != nval) {
+		list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+			if (nval == IPVLAN_MODE_L3)
+				ipvlan->dev->flags |= IFF_NOARP;
+			else
+				ipvlan->dev->flags &= ~IFF_NOARP;
+		}
+		port->mode = nval;
+	}
+}
+
+static int ipvlan_port_create(struct net_device *dev)
+{
+	struct ipvl_port *port;
+	int err, idx;
+
+	if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK) {
+		netdev_err(dev, "Master is either lo or non-ether device\n");
+		return -EINVAL;
+	}
+	port = kzalloc(sizeof(struct ipvl_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	port->dev = dev;
+	port->mode = IPVLAN_MODE_L3;
+	INIT_LIST_HEAD(&port->ipvlans);
+	for (idx = 0; idx < IPVLAN_HASH_SIZE; idx++)
+		INIT_HLIST_HEAD(&port->hlhead[idx]);
+
+	err = netdev_rx_handler_register(dev, ipvlan_handle_frame, port);
+	if (err)
+		goto err;
+
+	dev->priv_flags |= IFF_IPVLAN_MASTER;
+	return 0;
+
+err:
+	kfree_rcu(port, rcu);
+	return err;
+}
+
+static void ipvlan_port_destroy(struct net_device *dev)
+{
+	struct ipvl_port *port = ipvlan_port_get_rtnl(dev);
+
+	dev->priv_flags &= ~IFF_IPVLAN_MASTER;
+	netdev_rx_handler_unregister(dev);
+	kfree_rcu(port, rcu);
+}
+
+/* ipvlan network devices have devices nesting below it and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key ipvlan_netdev_xmit_lock_key;
+static struct lock_class_key ipvlan_netdev_addr_lock_key;
+
+#define IPVLAN_FEATURES \
+	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+	 NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
+	 NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
+	 NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)
+
+#define IPVLAN_STATE_MASK \
+	((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+
+static void ipvlan_set_lockdep_class_one(struct net_device *dev,
+					 struct netdev_queue *txq,
+					 void *_unused)
+{
+	lockdep_set_class(&txq->_xmit_lock, &ipvlan_netdev_xmit_lock_key);
+}
+
+static void ipvlan_set_lockdep_class(struct net_device *dev)
+{
+	lockdep_set_class(&dev->addr_list_lock, &ipvlan_netdev_addr_lock_key);
+	netdev_for_each_tx_queue(dev, ipvlan_set_lockdep_class_one, NULL);
+}
+
+static int ipvlan_init(struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	const struct net_device *phy_dev = ipvlan->phy_dev;
+
+	dev->state = (dev->state & ~IPVLAN_STATE_MASK) |
+		     (phy_dev->state & IPVLAN_STATE_MASK);
+	dev->features = phy_dev->features & IPVLAN_FEATURES;
+	dev->features |= NETIF_F_LLTX;
+	dev->gso_max_size = phy_dev->gso_max_size;
+	dev->iflink = phy_dev->ifindex;
+	dev->hard_header_len = phy_dev->hard_header_len;
+
+	ipvlan_set_lockdep_class(dev);
+
+	ipvlan->pcpu_stats = alloc_percpu(struct ipvl_pcpu_stats);
+	if (!ipvlan->pcpu_stats)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ipvlan_uninit(struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_port *port = ipvlan->port;
+
+	if (ipvlan->pcpu_stats)
+		free_percpu(ipvlan->pcpu_stats);
+
+	port->count -= 1;
+	if (!port->count)
+		ipvlan_port_destroy(port->dev);
+}
+
+static int ipvlan_open(struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+	struct ipvl_addr *addr;
+
+	if (ipvlan->port->mode == IPVLAN_MODE_L3)
+		dev->flags |= IFF_NOARP;
+	else
+		dev->flags &= ~IFF_NOARP;
+
+	if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
+		list_for_each_entry(addr, &ipvlan->addrs, anode)
+			ipvlan_ht_addr_add(ipvlan, addr);
+	}
+	return dev_uc_add(phy_dev, phy_dev->dev_addr);
+}
+
+static int ipvlan_stop(struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+	struct ipvl_addr *addr;
+
+	dev_uc_unsync(phy_dev, dev);
+	dev_mc_unsync(phy_dev, dev);
+
+	dev_uc_del(phy_dev, phy_dev->dev_addr);
+
+	if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
+		list_for_each_entry(addr, &ipvlan->addrs, anode)
+			ipvlan_ht_addr_del(addr, !dev->dismantle);
+	}
+	return 0;
+}
+
+netdev_tx_t ipvlan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+	int skblen = skb->len;
+	int ret;
+
+	ret = ipvlan_queue_xmit(skb, dev);
+	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
+		struct ipvl_pcpu_stats *pcptr;
+
+		pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
+
+		u64_stats_update_begin(&pcptr->syncp);
+		pcptr->tx_pkts++;
+		pcptr->tx_bytes += skblen;
+		u64_stats_update_end(&pcptr->syncp);
+	} else {
+		this_cpu_inc(ipvlan->pcpu_stats->tx_drps);
+	}
+	return ret;
+}
+
+static netdev_features_t ipvlan_fix_features(struct net_device *dev,
+					     netdev_features_t features)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	return features & (ipvlan->sfeatures | ~IPVLAN_FEATURES);
+}
+
+static void ipvlan_change_rx_flags(struct net_device *dev, int change)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+
+	if (change & IFF_ALLMULTI)
+		dev_set_allmulti(phy_dev, dev->flags & IFF_ALLMULTI? 1 : -1);
+}
+
+static void ipvlan_set_broadcast_mac_filter(struct ipvl_dev *ipvlan, bool set)
+{
+	struct net_device *dev = ipvlan->dev;
+	unsigned int hashbit = ipvlan_mac_hash(dev->broadcast);
+
+	if (set && !test_bit(hashbit, ipvlan->mac_filters))
+		__set_bit(hashbit, ipvlan->mac_filters);
+	else if (!set && test_bit(hashbit, ipvlan->mac_filters))
+		__clear_bit(hashbit, ipvlan->mac_filters);
+}
+
+static void ipvlan_set_multicast_mac_filter(struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+		bitmap_fill(ipvlan->mac_filters, IPVLAN_MAC_FILTER_SIZE);
+	} else {
+		struct netdev_hw_addr *ha;
+		DECLARE_BITMAP(mc_filters, IPVLAN_MAC_FILTER_SIZE);
+
+		bitmap_zero(mc_filters, IPVLAN_MAC_FILTER_SIZE);
+		netdev_for_each_mc_addr(ha, dev)
+			__set_bit(ipvlan_mac_hash(ha->addr), mc_filters);
+
+		bitmap_copy(ipvlan->mac_filters, mc_filters,
+			    IPVLAN_MAC_FILTER_SIZE);
+	}
+	dev_uc_sync(ipvlan->phy_dev, dev);
+	dev_mc_sync(ipvlan->phy_dev, dev);
+}
+
+static struct rtnl_link_stats64 *ipvlan_get_stats64(struct net_device *dev,
+						    struct rtnl_link_stats64 *s)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	if (ipvlan->pcpu_stats) {
+		struct ipvl_pcpu_stats *pcptr;
+		u64 rx_pkts, rx_bytes, rx_mcast, tx_pkts, tx_bytes;
+		u32 rx_errs = 0, tx_drps = 0;
+		u32 strt;
+		int idx;
+
+		for_each_possible_cpu(idx) {
+			pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx);
+			do {
+				strt= u64_stats_fetch_begin_irq(&pcptr->syncp);
+				rx_pkts = pcptr->rx_pkts;
+				rx_bytes = pcptr->rx_bytes;
+				rx_mcast = pcptr->rx_mcast;
+				tx_pkts = pcptr->tx_pkts;
+				tx_bytes = pcptr->tx_bytes;
+			} while (u64_stats_fetch_retry_irq(&pcptr->syncp,
+							   strt));
+
+			s->rx_packets += rx_pkts;
+			s->rx_bytes += rx_bytes;
+			s->multicast += rx_mcast;
+			s->tx_packets += tx_pkts;
+			s->tx_bytes += tx_bytes;
+
+			/* u32 values are updated without syncp protection. */
+			rx_errs += pcptr->rx_errs;
+			tx_drps += pcptr->tx_drps;
+		}
+		s->rx_errors = rx_errs;
+		s->rx_dropped = rx_errs;
+		s->tx_dropped = tx_drps;
+	}
+	return s;
+}
+
+static int ipvlan_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+
+	return vlan_vid_add(phy_dev, proto, vid);
+}
+
+static int ipvlan_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
+				   u16 vid)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+
+	vlan_vid_del(phy_dev, proto, vid);
+	return 0;
+}
+
+static const struct net_device_ops ipvlan_netdev_ops = {
+	.ndo_init		= ipvlan_init,
+	.ndo_uninit		= ipvlan_uninit,
+	.ndo_open		= ipvlan_open,
+	.ndo_stop		= ipvlan_stop,
+	.ndo_start_xmit		= ipvlan_start_xmit,
+	.ndo_fix_features	= ipvlan_fix_features,
+	.ndo_change_rx_flags	= ipvlan_change_rx_flags,
+	.ndo_set_rx_mode	= ipvlan_set_multicast_mac_filter,
+	.ndo_get_stats64	= ipvlan_get_stats64,
+	.ndo_vlan_rx_add_vid	= ipvlan_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= ipvlan_vlan_rx_kill_vid,
+};
+
+static int ipvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
+			      unsigned short type, const void *daddr,
+			      const void *saddr, unsigned len)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct net_device *phy_dev = ipvlan->phy_dev;
+
+	/* TODO Probably use a different field than dev_addr so that the
+	 * mac-address on the virtual device is portable and can be carried
+	 * while the packets use the mac-addr on the physical device.
+	 */
+	return dev_hard_header(skb, phy_dev, type, daddr,
+			       saddr ? : dev->dev_addr, len);
+}
+
+static const struct header_ops ipvlan_header_ops = {
+	.create  	= ipvlan_hard_header,
+	.rebuild	= eth_rebuild_header,
+	.parse		= eth_header_parse,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
+static int ipvlan_ethtool_get_settings(struct net_device *dev,
+				       struct ethtool_cmd *cmd)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	return __ethtool_get_settings(ipvlan->phy_dev, cmd);
+}
+
+static void ipvlan_ethtool_get_drvinfo(struct net_device *dev,
+				       struct ethtool_drvinfo *drvinfo)
+{
+	strlcpy(drvinfo->driver, IPVLAN_DRV, sizeof(drvinfo->driver));
+	strlcpy(drvinfo->version, IPV_DRV_VER, sizeof(drvinfo->version));
+}
+
+static u32 ipvlan_ethtool_get_msglevel(struct net_device *dev)
+{
+	const struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	return ipvlan->msg_enable;
+}
+
+static void ipvlan_ethtool_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	ipvlan->msg_enable = value;
+}
+
+static const struct ethtool_ops ipvlan_ethtool_ops = {
+	.get_link	= ethtool_op_get_link,
+	.get_settings	= ipvlan_ethtool_get_settings,
+	.get_drvinfo	= ipvlan_ethtool_get_drvinfo,
+	.get_msglevel	= ipvlan_ethtool_get_msglevel,
+	.set_msglevel	= ipvlan_ethtool_set_msglevel,
+};
+
+static int ipvlan_nl_changelink(struct net_device *dev,
+				struct nlattr *tb[], struct nlattr *data[])
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev);
+
+	if (data && data[IFLA_IPVLAN_MODE]) {
+		u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
+
+		ipvlan_set_port_mode(port, nmode);
+	}
+	return 0;
+}
+
+static size_t ipvlan_nl_getsize(const struct net_device *dev)
+{
+	return (0
+		+ nla_total_size(2) /* IFLA_IPVLAN_MODE */
+		);
+}
+
+static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (data && data[IFLA_IPVLAN_MODE]) {
+		u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
+
+		if (mode < IPVLAN_MODE_L2 || mode >= IPVLAN_MODE_MAX)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int ipvlan_nl_fillinfo(struct sk_buff *skb,
+			      const struct net_device *dev)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev);
+	int ret = -EINVAL;
+
+	if (!port)
+		goto err;
+
+	ret = -EMSGSIZE;
+	if (nla_put_u16(skb, IFLA_IPVLAN_MODE, port->mode))
+		goto err;
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
+			   struct nlattr *tb[], struct nlattr *data[])
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_port *port;
+	struct net_device *phy_dev;
+	int err;
+
+	if (!tb[IFLA_LINK])
+		return -EINVAL;
+
+	phy_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
+	if (!phy_dev)
+		return -ENODEV;
+
+	if (ipvlan_dev_slave(phy_dev)) {
+		struct ipvl_dev *tmp = netdev_priv(phy_dev);
+
+		phy_dev = tmp->phy_dev;
+	} else if (!ipvlan_dev_master(phy_dev)) {
+		err = ipvlan_port_create(phy_dev);
+		if (err < 0)
+			return err;
+	}
+
+	port = ipvlan_port_get_rtnl(phy_dev);
+	if (data && data[IFLA_IPVLAN_MODE])
+		port->mode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
+
+	ipvlan->phy_dev = phy_dev;
+	ipvlan->dev = dev;
+	ipvlan->port = port;
+	ipvlan->sfeatures = IPVLAN_FEATURES;
+	INIT_LIST_HEAD(&ipvlan->addrs);
+	ipvlan->ipv4cnt = 0;
+	ipvlan->ipv6cnt = 0;
+
+	/* TODO Probably put random address here to be presented to the
+	 * world but keep using the physical-dev address for the outgoing
+	 * packets.
+	 */
+	memcpy(dev->dev_addr, phy_dev->dev_addr, ETH_ALEN);
+
+	dev->priv_flags |= IFF_IPVLAN_SLAVE;
+
+	port->count += 1;
+	err = register_netdevice(dev);
+	if (err < 0)
+		goto ipvlan_destroy_port;
+
+	err = netdev_upper_dev_link(phy_dev, dev);
+	if (err)
+		goto ipvlan_destroy_port;
+
+	list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
+	netif_stacked_transfer_operstate(phy_dev, dev);
+	return 0;
+
+ipvlan_destroy_port:
+	port->count -= 1;
+	if (!port->count)
+		ipvlan_port_destroy(phy_dev);
+
+	return err;
+}
+
+static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct ipvl_addr *addr, *next;
+
+	if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
+		list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
+			ipvlan_ht_addr_del(addr, !dev->dismantle);
+			list_del_rcu(&addr->anode);
+		}
+	}
+	list_del_rcu(&ipvlan->pnode);
+	unregister_netdevice_queue(dev, head);
+	netdev_upper_dev_unlink(ipvlan->phy_dev, dev);
+}
+
+static void ipvlan_link_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+	dev->priv_flags |= IFF_UNICAST_FLT;
+	dev->netdev_ops = &ipvlan_netdev_ops;
+	dev->destructor = free_netdev;
+	dev->header_ops = &ipvlan_header_ops;
+	dev->ethtool_ops = &ipvlan_ethtool_ops;
+	dev->tx_queue_len = 0;
+}
+
+static const struct nla_policy ipvlan_nl_policy[IFLA_IPVLAN_MAX + 1] =
+{
+	[IFLA_IPVLAN_MODE] = { .type = NLA_U16 },
+};
+
+static struct rtnl_link_ops ipvlan_link_ops = {
+	.kind		= "ipvlan",
+	.priv_size	= sizeof(struct ipvl_dev),
+
+	.get_size	= ipvlan_nl_getsize,
+	.policy		= ipvlan_nl_policy,
+	.validate	= ipvlan_nl_validate,
+	.fill_info	= ipvlan_nl_fillinfo,
+	.changelink	= ipvlan_nl_changelink,
+	.maxtype	= IFLA_IPVLAN_MAX,
+
+	.setup		= ipvlan_link_setup,
+	.newlink	= ipvlan_link_new,
+	.dellink	= ipvlan_link_delete,
+};
+
+int ipvlan_link_register(struct rtnl_link_ops *ops)
+{
+	return rtnl_link_register(ops);
+}
+
+static int ipvlan_device_event(struct notifier_block *unused,
+			       unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct ipvl_dev *ipvlan, *next;
+	struct ipvl_port *port;
+	LIST_HEAD(lst_kill);
+
+	if (!ipvlan_dev_master(dev))
+		return NOTIFY_DONE;
+
+	port = ipvlan_port_get_rtnl(dev);
+
+	switch (event) {
+	case NETDEV_CHANGE:
+		list_for_each_entry(ipvlan, &port->ipvlans, pnode)
+			netif_stacked_transfer_operstate(ipvlan->phy_dev,
+							 ipvlan->dev);
+		break;
+
+	case NETDEV_UNREGISTER:
+		if (dev->reg_state != NETREG_UNREGISTERING)
+			break;
+
+		list_for_each_entry_safe(ipvlan, next, &port->ipvlans,
+					 pnode)
+			ipvlan->dev->rtnl_link_ops->dellink(ipvlan->dev,
+							    &lst_kill);
+		unregister_netdevice_many(&lst_kill);
+		break;
+
+	case NETDEV_FEAT_CHANGE:
+		list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
+			ipvlan->dev->features = dev->features & IPVLAN_FEATURES;
+			ipvlan->dev->gso_max_size = dev->gso_max_size;
+			netdev_features_change(ipvlan->dev);
+		}
+		break;
+
+	case NETDEV_CHANGEMTU:
+		list_for_each_entry(ipvlan, &port->ipvlans, pnode)
+			ipvlan_adjust_mtu(ipvlan, dev);
+		break;
+
+	case NETDEV_PRE_TYPE_CHANGE:
+		/* Forbid underlying device to change its type. */
+		return NOTIFY_BAD;
+	}
+	return NOTIFY_DONE;
+}
+
+static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+{
+	struct ipvl_addr *addr;
+
+	if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) {
+		netif_err(ipvlan, ifup, ipvlan->dev,
+			  "Failed to add IPv6=%pI6c addr for %s intf\n",
+			  ip6_addr, ipvlan->dev->name);
+		return -EINVAL;
+	}
+	addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC);
+	if (!addr)
+		return -ENOMEM;
+
+	addr->master = ipvlan;
+	memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
+	addr->atype = IPVL_IPV6;
+	list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+	ipvlan->ipv6cnt++;
+	ipvlan_ht_addr_add(ipvlan, addr);
+
+	return 0;
+}
+
+static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+{
+	struct ipvl_addr *addr;
+
+	addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true);
+	if (!addr)
+		return;
+
+	ipvlan_ht_addr_del(addr, true);
+	list_del_rcu(&addr->anode);
+	ipvlan->ipv6cnt--;
+	WARN_ON(ipvlan->ipv6cnt < 0);
+	kfree_rcu(addr, rcu);
+
+	return;
+}
+
+static int ipvlan_addr6_event(struct notifier_block *unused,
+			      unsigned long event, void *ptr)
+{
+	struct inet6_ifaddr *if6 = (struct inet6_ifaddr *)ptr;
+	struct net_device *dev = (struct net_device *)if6->idev->dev;
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	if (!ipvlan_dev_slave(dev))
+		return NOTIFY_DONE;
+
+	if (!ipvlan || !ipvlan->port)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_UP:
+		if (ipvlan_add_addr6(ipvlan, &if6->addr))
+			return NOTIFY_BAD;
+		break;
+
+	case NETDEV_DOWN:
+		ipvlan_del_addr6(ipvlan, &if6->addr);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
+{
+	struct ipvl_addr *addr;
+
+	if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) {
+		netif_err(ipvlan, ifup, ipvlan->dev,
+			  "Failed to add IPv4=%pI4 on %s intf.\n",
+			  ip4_addr, ipvlan->dev->name);
+		return -EINVAL;
+	}
+	addr = kzalloc(sizeof(struct ipvl_addr), GFP_KERNEL);
+	if (!addr)
+		return -ENOMEM;
+
+	addr->master = ipvlan;
+	memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
+	addr->atype = IPVL_IPV4;
+	list_add_tail_rcu(&addr->anode, &ipvlan->addrs);
+	ipvlan->ipv4cnt++;
+	ipvlan_ht_addr_add(ipvlan, addr);
+	ipvlan_set_broadcast_mac_filter(ipvlan, true);
+
+	return 0;
+}
+
+static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
+{
+	struct ipvl_addr *addr;
+
+	addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false);
+	if (!addr)
+		return;
+
+	ipvlan_ht_addr_del(addr, true);
+	list_del_rcu(&addr->anode);
+	ipvlan->ipv4cnt--;
+	WARN_ON(ipvlan->ipv4cnt < 0);
+	if (!ipvlan->ipv4cnt)
+	    ipvlan_set_broadcast_mac_filter(ipvlan, false);
+	kfree_rcu(addr, rcu);
+
+	return;
+}
+
+static int ipvlan_addr4_event(struct notifier_block *unused,
+			      unsigned long event, void *ptr)
+{
+	struct in_ifaddr *if4 = (struct in_ifaddr *)ptr;
+	struct net_device *dev = (struct net_device *)if4->ifa_dev->dev;
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+	struct in_addr ip4_addr;
+
+	if (!ipvlan_dev_slave(dev))
+		return NOTIFY_DONE;
+
+	if (!ipvlan || !ipvlan->port)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_UP:
+		ip4_addr.s_addr = if4->ifa_address;
+		if (ipvlan_add_addr4(ipvlan, &ip4_addr))
+			return NOTIFY_BAD;
+		break;
+
+	case NETDEV_DOWN:
+		ip4_addr.s_addr = if4->ifa_address;
+		ipvlan_del_addr4(ipvlan, &ip4_addr);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = {
+	.notifier_call = ipvlan_addr4_event,
+};
+
+static struct notifier_block ipvlan_notifier_block __read_mostly = {
+	.notifier_call = ipvlan_device_event,
+};
+
+static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
+	.notifier_call = ipvlan_addr6_event,
+};
+
+static int __init ipvlan_init_module(void)
+{
+	int err;
+
+	ipvlan_init_secret();
+	register_netdevice_notifier(&ipvlan_notifier_block);
+	register_inet6addr_notifier(&ipvlan_addr6_notifier_block);
+	register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
+
+	err = ipvlan_link_register(&ipvlan_link_ops);
+	if (err < 0)
+		goto error;
+
+	return 0;
+error:
+	unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
+	unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
+	unregister_netdevice_notifier(&ipvlan_notifier_block);
+	return err;
+}
+
+static void __exit ipvlan_cleanup_module(void)
+{
+	rtnl_link_unregister(&ipvlan_link_ops);
+	unregister_netdevice_notifier(&ipvlan_notifier_block);
+	unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
+	unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
+}
+
+module_init(ipvlan_init_module);
+module_exit(ipvlan_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mahesh Bandewar <maheshb@google.com>");
+MODULE_DESCRIPTION("Driver for L3 (IPv6/IPv4) based VLANs");
+MODULE_ALIAS_RTNL_LINK("ipvlan");
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5cd508787572..2cb772495f7a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1230,6 +1230,8 @@ enum netdev_priv_flags {
 	IFF_LIVE_ADDR_CHANGE		= 1<<20,
 	IFF_MACVLAN			= 1<<21,
 	IFF_XMIT_DST_RELEASE_PERM	= 1<<22,
+	IFF_IPVLAN_MASTER		= 1<<23,
+	IFF_IPVLAN_SLAVE		= 1<<24,
 };
 
 #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
@@ -1255,6 +1257,8 @@ enum netdev_priv_flags {
 #define IFF_LIVE_ADDR_CHANGE		IFF_LIVE_ADDR_CHANGE
 #define IFF_MACVLAN			IFF_MACVLAN
 #define IFF_XMIT_DST_RELEASE_PERM	IFF_XMIT_DST_RELEASE_PERM
+#define IFF_IPVLAN_MASTER		IFF_IPVLAN_MASTER
+#define IFF_IPVLAN_SLAVE		IFF_IPVLAN_SLAVE
 
 /**
  *	struct net_device - The DEVICE structure.
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 7072d8325016..36bddc233633 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -330,6 +330,21 @@ enum macvlan_macaddr_mode {
 
 #define MACVLAN_FLAG_NOPROMISC	1
 
+/* IPVLAN section */
+enum {
+	IFLA_IPVLAN_UNSPEC,
+	IFLA_IPVLAN_MODE,
+	__IFLA_IPVLAN_MAX
+};
+
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+
+enum ipvlan_mode {
+	IPVLAN_MODE_L2 = 0,
+	IPVLAN_MODE_L3,
+	IPVLAN_MODE_MAX
+};
+
 /* VXLAN section */
 enum {
 	IFLA_VXLAN_UNSPEC,
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related

* Re: [PATCH net-next] vlan: Pass ethtool get_ts_info queries to real device.
From: Richard Cochran @ 2014-11-24  7:38 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: David Miller, netdev, stefan.sorensen
In-Reply-To: <1416769497.7215.56.camel@decadent.org.uk>

On Sun, Nov 23, 2014 at 07:04:57PM +0000, Ben Hutchings wrote:
> The two datasheets I've looked at so far (EG20T for pch_gbe driver,
> BF518 for bfin_mac driver) mention support for 802.1q but not 802.1ad.
> I already mentioned ptp_classify.c doesn't support 802.1ad, and I can't
> see how it would ever make sense to run PTP directly over 802.1ad
> anyway.

Me, neither.
 
> I'll read some more datasheets to see whether 802.1q is generally
> supported, but for 802.1ad VLAN devices I think we should pass-through
> only the NONE and ALL filter capabilities.

Fine with me.

Thanks,
Richard

^ permalink raw reply

* Re: [PATCH net-net 0/4] Increase the limit of tuntap queues
From: Michael S. Tsirkin @ 2014-11-24  7:55 UTC (permalink / raw)
  To: Jason Wang
  Cc: David Miller, pagupta, linux-kernel, netdev, dgibson, vfalico,
	edumazet, vyasevic, hkchu, wuzhy, xemul, therbert, bhutchings,
	xii, stephen, jiri, sergei.shtylyov
In-Reply-To: <5472A499.60906@redhat.com>

On Mon, Nov 24, 2014 at 11:23:05AM +0800, Jason Wang wrote:
> On 11/23/2014 06:46 PM, Michael S. Tsirkin wrote:
> > On Wed, Nov 19, 2014 at 10:44:27PM +0200, Michael S. Tsirkin wrote:
> >> > On Wed, Nov 19, 2014 at 03:16:28PM -0500, David Miller wrote:
> >>> > > From: Pankaj Gupta <pagupta@redhat.com>
> >>> > > Date: Tue, 18 Nov 2014 21:52:54 +0530
> >>> > > 
> >>>> > > > - Accept maximum number of queues as sysctl param so that any user space 
> >>>> > > >   application like libvirt can use this value to limit number of queues. Also
> >>>> > > >   Administrators can specify maximum number of queues by updating this sysctl
> >>>> > > >   entry.
> >>> > > 
> >>> > > This is the only part I don't like.
> >>> > > 
> >>> > > Just let whoever has privileges to configure the tun device shoot
> >>> > > themselves in the foot if they want to by configuring "too many"
> >>> > > queues.
> >>> > > 
> >>> > > If the virtual entity runs itself out of resources by doing something
> >>> > > stupid, it's purely their problem.
> >> > 
> >> > Well it will run host out of kernel, no?
> > To clarify:
> >
> > At the moment attaching/detaching queues is an unpriveledged operation.
> >
> > Shouldn't we worry that an application can cause large
> > allocations, and provide a way to limit these?
> 
> But creating new queues (TUNSETIFF) is privileged. There's no way for
> unprivileged user to allocate more resources. So we are safe here?

Hmm, that's true, I think I was confused.
Thanks for setting me straight.

-- 
MST

^ permalink raw reply

* Re: [PATCH net-net 0/4] Increase the limit of tuntap queues
From: Michael S. Tsirkin @ 2014-11-24  8:02 UTC (permalink / raw)
  To: David Miller
  Cc: pagupta, linux-kernel, netdev, jasowang, dgibson, vfalico,
	edumazet, vyasevic, hkchu, wuzhy, xemul, therbert, bhutchings,
	xii, stephen, jiri, sergei.shtylyov
In-Reply-To: <20141123.202321.1426718936320546377.davem@davemloft.net>

On Sun, Nov 23, 2014 at 08:23:21PM -0500, David Miller wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Sun, 23 Nov 2014 22:30:32 +0200
> 
> > qemu runs in the host, but it's unpriveledged: it gets
> > passed tun FDs by a priveledged daemon, and it only
> > has the rights to some operations,
> > in particular to attach and detach queues.
> > 
> > The assumption always was that this operation is safe
> > and can't make kernel run out of resources.
> 
> This creates a rather rediculous situation in my opinion.
> 
> Configuring a network device is a privileged operation, the daemon
> should be setting this thing up.
> 
> In no other context would we have to worry about something like this.

Right.  Jason corrected me.  I got it wrong:
what qemu does is TUNSETQUEUE and that needs to get a queue
that's already initialized by the daemon.

To create new queues daemon calls TUNSETIFF,
and that already can be used to create new devices,
so it's a priveledged operation.

This means it's safe to just drop the restriction,
exactly as you suggested originally.
-- 
MST

^ permalink raw reply

* [PATCH net_test_tools] route_bench: Fix bug in DST_ITERATE option
From: Vijay Subramanian @ 2014-11-24  8:13 UTC (permalink / raw)
  To: netdev; +Cc: davem, Vijay Subramanian

While setting option for dst_addr_stride, flags should be set for
FLAG_DST_ITERATE not FLAG_SRC_ITERATE.

Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
---
 route_bench.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/route_bench.c b/route_bench.c
index eb91dcf..22cbd2a 100644
--- a/route_bench.c
+++ b/route_bench.c
@@ -292,7 +292,7 @@ int main(int argc, char **argv, char **envp)
 			break;
 		case 'e':
 			sscanf(optarg, "%u", &s->dst_addr_stride);
-			s->flags |= FLAG_SRC_ITERATE;
+			s->flags |= FLAG_DST_ITERATE;
 			break;
 		case 'f':
 			s->dst_addr_limit = inet_addr(optarg);
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH] mdio-mux-gpio: Use GPIO descriptor interface and new gpiod_set_array function
From: Rojhalat Ibrahim @ 2014-11-24  8:35 UTC (permalink / raw)
  To: David Miller
  Cc: f.fainelli, netdev, david.daney, linux-gpio, linus.walleij,
	acourbot
In-Reply-To: <20141121.151301.477197043372693075.davem@davemloft.net>

On Friday 21 November 2014 15:13:01 David Miller wrote:
> From: Rojhalat Ibrahim <imr@rtschenk.de>
> Date: Thu, 20 Nov 2014 13:24:44 +0100
> 
> > Convert mdio-mux-gpio to the GPIO descriptor interface and use the new
> > gpiod_set_array function to set all output signals simultaneously.
> > 
> > Signed-off-by: Rojhalat Ibrahim <imr@rtschenk.de>
> > --
> > This patch depends on the gpiod_set_array function, which is available in
> > the linux-gpio devel tree.
> 
> Then I really can't apply it to the networking GIT tree.
> 

Then maybe you could ack the patch and then Linus Walleij could apply it to
the GPIO tree, right?

   Rojhalat



^ permalink raw reply

* Re: [PATCH 0/6] kernel tinification: optionally compile out splice family of syscalls (splice, vmsplice, tee and sendfile)
From: Geert Uytterhoeven @ 2014-11-24  8:38 UTC (permalink / raw)
  To: Josh Triplett
  Cc: Pieter Smith, David Miller,
	alexander.h.duyck-ral2JQCrhuEAvxtiuMwx3w, Al Viro,
	Alexei Starovoitov, Andrew Morton, beber-2YnHqweIUXrk1uMJSBkQmQ,
	catalina.mocanu-Re5JQEeQqe8AvxtiuMwx3w, Daniel Borkmann,
	Eric Dumazet, Eric W. Biederman, Fabian Frederick,
	fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Hugh Dickins,
	iulia.manda21-Re5JQEeQqe8AvxtiuMwx3w, Jan Beulich,
	bfields-uC3wQj2KruNg9hUCZPvPmw, jlayton-vpEMnDpepFuMZCB2o+C8xQ,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Linux FS Devel,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Luis R. Rodriguez, Matt Turner, Mel Gorman, Michael S. Tsirkin,
	Miklos 
In-Reply-To: <20141123233637.GC12456@thin>

On Mon, Nov 24, 2014 at 12:36 AM, Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:
> On Sun, Nov 23, 2014 at 09:30:40PM +0100, Pieter Smith wrote:
>> On Sun, Nov 23, 2014 at 11:43:26AM -0800, Josh Triplett wrote:
>> > On Sun, Nov 23, 2014 at 01:46:23PM -0500, David Miller wrote:
>> > > Truly removing sendfile/sendpage means that you can't even compile NFS
>> > > into the tree.
>> >
>> > If you mean the in-kernel nfsd (CONFIG_NFSD), that already has a large
>> > stack of "select" and "depends on", both directly and indirectly; adding
>> > a "select SPLICE_SYSCALL" to it seems fine.  (That select does need
>> > adding, though.  Pieter, you need to test-compile more than just
>> > tinyconfig and defconfig.  Try an allyesconfig with *just* splice turned
>> > off, and make sure that compiles.)
>>
>> Did exacly that. Took forever on my hardware, but no problems.
>
> Ah, I see.  Looking more closely at nfsd, it looks like it already has a
> code path for filesystems that don't do splice.  I think, rather than
> making nfsd select SPLICE_SYSCALL, that it would suffice to change the
> "rqstp->rq_splice_ok = true;" in svc_process_common (net/sunrpc/svc.c)
> to:
>
> rqstp->rq_splice_ok = IS_ENABLED(CONFIG_SPLICE_SYSCALL);
>
> Then nfsd should simply *always* fall back to its non-splice support.

Hence I suggest adding to the nfsd help text:

    While nfsd works without SPLICE_SYSCALL, you may want to enable
    SPLICE_SYSCALL for <...> (performance?) reasons.

(Hmm, does Kconfig need a "suggests", cfr. Debian package dependencies?)

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 2/2] sh_eth: Fix asynchronous external abort
From: Geert Uytterhoeven @ 2014-11-24  8:41 UTC (permalink / raw)
  To: Simon Horman
  Cc: Yoshihiro Kaneko, netdev@vger.kernel.org, David S. Miller,
	Magnus Damm, Linux-sh list
In-Reply-To: <20141124011759.GA5089@verge.net.au>

On Mon, Nov 24, 2014 at 2:18 AM, Simon Horman <horms@verge.net.au> wrote:
> On Thu, Nov 13, 2014 at 04:02:15PM +0900, Yoshihiro Kaneko wrote:
>> From: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
>>
>> When clock is disabled, Ethernet register access raise Bus error.
>
> I have spoken with Kimura-san and the problem may be reproduced by
> calling ethtool with -s of -G while the network interface is down.
>
> e.g.:
> ifconfig eth0 down
> ethtool -G eth0 rx 512

That makes sense.

I think it would be good to add the reproduction steps to the commit message.

> I have confirmed that the problem above appears in net-next
> and appears to be resolved with this patch and the previous on
> in this series (which seems to be a dependency) applied.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 0/6] kernel tinification: optionally compile out splice family of syscalls (splice, vmsplice, tee and sendfile)
From: Josh Triplett @ 2014-11-24  9:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Pieter Smith, David Miller,
	alexander.h.duyck-ral2JQCrhuEAvxtiuMwx3w, Al Viro,
	Alexei Starovoitov, Andrew Morton, beber-2YnHqweIUXrk1uMJSBkQmQ,
	catalina.mocanu-Re5JQEeQqe8AvxtiuMwx3w, Daniel Borkmann,
	Eric Dumazet, Eric W. Biederman, Fabian Frederick,
	fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Hugh Dickins,
	iulia.manda21-Re5JQEeQqe8AvxtiuMwx3w, Jan Beulich,
	bfields-uC3wQj2KruNg9hUCZPvPmw, jlayton-vpEMnDpepFuMZCB2o+C8xQ,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Linux FS Devel,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Luis R. Rodriguez, Matt Turner, Mel Gorman, Michael S. Tsirkin,
	Miklos 
In-Reply-To: <CAMuHMdW8gAiyFiPHu-N4Dg_+b6Qg9JXZZ3PqOn=VmZLcEH-Xkg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Mon, Nov 24, 2014 at 09:38:20AM +0100, Geert Uytterhoeven wrote:
> On Mon, Nov 24, 2014 at 12:36 AM, Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:
> > On Sun, Nov 23, 2014 at 09:30:40PM +0100, Pieter Smith wrote:
> >> On Sun, Nov 23, 2014 at 11:43:26AM -0800, Josh Triplett wrote:
> >> > On Sun, Nov 23, 2014 at 01:46:23PM -0500, David Miller wrote:
> >> > > Truly removing sendfile/sendpage means that you can't even compile NFS
> >> > > into the tree.
> >> >
> >> > If you mean the in-kernel nfsd (CONFIG_NFSD), that already has a large
> >> > stack of "select" and "depends on", both directly and indirectly; adding
> >> > a "select SPLICE_SYSCALL" to it seems fine.  (That select does need
> >> > adding, though.  Pieter, you need to test-compile more than just
> >> > tinyconfig and defconfig.  Try an allyesconfig with *just* splice turned
> >> > off, and make sure that compiles.)
> >>
> >> Did exacly that. Took forever on my hardware, but no problems.
> >
> > Ah, I see.  Looking more closely at nfsd, it looks like it already has a
> > code path for filesystems that don't do splice.  I think, rather than
> > making nfsd select SPLICE_SYSCALL, that it would suffice to change the
> > "rqstp->rq_splice_ok = true;" in svc_process_common (net/sunrpc/svc.c)
> > to:
> >
> > rqstp->rq_splice_ok = IS_ENABLED(CONFIG_SPLICE_SYSCALL);
> >
> > Then nfsd should simply *always* fall back to its non-splice support.
> 
> Hence I suggest adding to the nfsd help text:
> 
>     While nfsd works without SPLICE_SYSCALL, you may want to enable
>     SPLICE_SYSCALL for <...> (performance?) reasons.

It already seems sufficiently unlikely to enable NFSD while disabling
SPLICE_SYSCALL (in the latter case, turning on EXPERT to do so).  It
doesn't seem worth adding such a note to NFSD.  At most, I'd say that
NFSD might want a note somewhere in its documentation saying that it
takes advantage of filesystems with splice support if serving files from
one, and if running on a kernel that has splice.

> (Hmm, does Kconfig need a "suggests", cfr. Debian package dependencies?)

Perhaps, though that seems much lower priority than, for instance,
transitive "select".

- Josh Triplett

^ permalink raw reply

* Re: [fuse-devel] [PATCH 4/6] fs/fuse: support compiling out splice
From: Pieter Smith @ 2014-11-24  9:49 UTC (permalink / raw)
  To: Josh Triplett
  Cc: Richard Weinberger, Michael S. Tsirkin, Bertrand Jacquin,
	Oleg Nesterov, J. Bruce Fields, Eric Dumazet,
	蔡正龙, Jeff Layton, Tom Herbert,
	Alexei Starovoitov, Miklos Szeredi, Peter Foley, Hugh Dickins,
	Xiao Guangrong, Geert Uytterhoeven, Mel Gorman, Matt Turner,
	Paul E. McKenney, Alexander Duyck, open list:FUSE: FILESYSTEM...,
	Luis R. Rodriguez
In-Reply-To: <20141123232302.GA12456@thin>

On Sun, Nov 23, 2014 at 03:23:02PM -0800, Josh Triplett wrote:
> On Sun, Nov 23, 2014 at 11:29:08PM +0100, Richard Weinberger wrote:
> > On Sun, Nov 23, 2014 at 3:20 PM, Pieter Smith <pieter@boesman.nl> wrote:
> > > To implement splice support, fs/fuse makes use of nosteal_pipe_buf_ops. This
> > > struct is exported by fs/splice. The goal of the larger patch set is to
> > > completely compile out fs/splice, so uses of the exported struct need to be
> > > compiled out along with fs/splice.
> > >
> > > This patch therefore compiles out splice support in fs/fuse when
> > > CONFIG_SYSCALL_SPLICE is undefined.
> > >
> > > Signed-off-by: Pieter Smith <pieter@boesman.nl>
> > > ---
> > >  fs/fuse/dev.c      | 4 ++--
> > >  include/linux/fs.h | 6 ++++++
> > >  2 files changed, 8 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> > > index ca88731..f8f92a4 100644
> > > --- a/fs/fuse/dev.c
> > > +++ b/fs/fuse/dev.c
> > > @@ -1291,7 +1291,7 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
> > >         return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
> > >  }
> > >
> > > -static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
> > > +static ssize_t __maybe_unused fuse_dev_splice_read(struct file *in, loff_t *ppos,
> > >                                     struct pipe_inode_info *pipe,
> > >                                     size_t len, unsigned int flags)
> > >  {
> > > @@ -2144,7 +2144,7 @@ const struct file_operations fuse_dev_operations = {
> > >         .llseek         = no_llseek,
> > >         .read           = do_sync_read,
> > >         .aio_read       = fuse_dev_read,
> > > -       .splice_read    = fuse_dev_splice_read,
> > > +       .splice_read    = __splice_p(fuse_dev_splice_read),
> > >         .write          = do_sync_write,
> > >         .aio_write      = fuse_dev_write,
> > >         .splice_write   = fuse_dev_splice_write,
> > > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > > index a957d43..04c0975 100644
> > > --- a/include/linux/fs.h
> > > +++ b/include/linux/fs.h
> > > @@ -2443,6 +2443,12 @@ extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
> > >                         int datasync);
> > >  extern void block_sync_page(struct page *page);
> > >
> > > +#ifdef CONFIG_SYSCALL_SPLICE
> > > +#define __splice_p(x) x
> > > +#else
> > > +#define __splice_p(x) NULL
> > > +#endif
> > > +
> > 
> > This needs to go into a different patch.
> > One logical change per patch please. :-)
> 
> Easy enough to merge this one into the patch introducing
> CONFIG_SYSCALL_SPLICE, then.
> 
> - Josh Triplett

The patch introducing CONFIG_SYSCALL_SPLICE (PATCH 3) only compiles out the
syscalls. PATCH 6 on the other hand, compiles out fs/splice.c. This patch
allows fs/fuse to be compiled when fs/splice.c is compiled out. If I am to
squash it, it would be logical to include it in PATCH 6, not 3.

Is this agreeable?

PATCH 5 does the same as this one for net/core. Should I still keep PATCH 5
separate from a maintainership perspective?

- Pieter Smith

^ permalink raw reply

* Re: [PATCH] xen-netback: do not report success if xenvif_alloc() fails
From: Wei Liu @ 2014-11-24 10:00 UTC (permalink / raw)
  To: Alexey Khoroshilov
  Cc: Ian Campbell, Wei Liu, xen-devel, netdev, linux-kernel,
	ldv-project
In-Reply-To: <1416610588-19816-1-git-send-email-khoroshilov@ispras.ru>

On Sat, Nov 22, 2014 at 01:56:28AM +0300, Alexey Khoroshilov wrote:
> If xenvif_alloc() failes, netback_probe() reports success as well as
> "online" uevent is emitted. It does not make any sense, but it just

Sorry, I don't follow. KOBJ_ONLINE event is not emitted in the event of
xenvif_alloc fails, is it?

> misleads users.
> 
> The patch implements propagation of error code if xenvif creation fails.
> 

This patch not only implements propagation of error code when xenvif
creation fails, but also when xenbus_scanf fails. You can simply write
"This patch implements propagation of error code for
backend_create_xenvif".

The rest of this patch looks good to me. Can you rewrite commit message
and resubmit, thanks.

Wei.

^ permalink raw reply

* Re: [PATCH 0/6] kernel tinification: optionally compile out splice family of syscalls (splice, vmsplice, tee and sendfile)
From: Pieter Smith @ 2014-11-24 10:01 UTC (permalink / raw)
  To: Josh Triplett
  Cc: Jeff Layton, David Miller,
	alexander.h.duyck-ral2JQCrhuEAvxtiuMwx3w,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, ast-uqk4Ao+rVK5Wk0Htik3J/w,
	akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	beber-2YnHqweIUXrk1uMJSBkQmQ,
	catalina.mocanu-Re5JQEeQqe8AvxtiuMwx3w,
	dborkman-H+wXaHxf7aLQT0dZR+AlfA, edumazet-hpIqsD4AKlfQT0dZR+AlfA,
	ebiederm-aS9lmoZGLiVWk0Htik3J/w, fabf-AgBVmzD5pcezQB+pC5nmwQ,
	fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, hughd-hpIqsD4AKlfQT0dZR+AlfA,
	iulia.manda21-Re5JQEeQqe8AvxtiuMwx3w, JBeulich-IBi9RG/b67k,
	bfields-uC3wQj2KruNg9hUCZPvPmw, linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, mcgrof-IBi9RG/b67k,
	mattst88-Re5JQEeQqe8AvxtiuMwx3w, mgorman-l3A5Bk7waGM,
	mst-H+wXaHxf7aLQT0dZR+AlfA, miklos-sUDqSbJrdHQHWmgEVkV9KA,
	netdev-u79uwXL29TY76Z2rM5mHXA, oleg-H+wXaHxf7aLQT0dZR+AlfA,
	Paul.Durrant-Sxgqhf6Nn4DQT0dZR+AlfA,
	paulmck-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
	pefoley2-lY0TAiDIAFlBDgjK7y7TUQ, tgraf-G/eBtMaohhA,
	therbert-hpIqsD4AKlfQT0dZR+AlfA, willemb-hpIqsD4AKlfQT0dZR+AlfA,
	xiaoguangrong-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
	zhenglong.cai-TJRtMXcVgQTM1kAEIRd3EQ
In-Reply-To: <20141124003251.GA13590@thin>

On Sun, Nov 23, 2014 at 04:32:51PM -0800, Josh Triplett wrote:
> On Sun, Nov 23, 2014 at 07:28:10PM -0500, Jeff Layton wrote:
> > On Sun, 23 Nov 2014 15:36:37 -0800
> > Josh Triplett <josh-iaAMLnmF4UmaiuxdJuQwMA@public.gmane.org> wrote:
> > 
> > > On Sun, Nov 23, 2014 at 09:30:40PM +0100, Pieter Smith wrote:
> > > > On Sun, Nov 23, 2014 at 11:43:26AM -0800, Josh Triplett wrote:
> > > > > On Sun, Nov 23, 2014 at 01:46:23PM -0500, David Miller wrote:
> > > > > > Truly removing sendfile/sendpage means that you can't even compile NFS
> > > > > > into the tree.
> > > > > 
> > > > > If you mean the in-kernel nfsd (CONFIG_NFSD), that already has a large
> > > > > stack of "select" and "depends on", both directly and indirectly; adding
> > > > > a "select SPLICE_SYSCALL" to it seems fine.  (That select does need
> > > > > adding, though.  Pieter, you need to test-compile more than just
> > > > > tinyconfig and defconfig.  Try an allyesconfig with *just* splice turned
> > > > > off, and make sure that compiles.)
> > > > 
> > > > Did exacly that. Took forever on my hardware, but no problems.
> > > 
> > > Ah, I see.  Looking more closely at nfsd, it looks like it already has a
> > > code path for filesystems that don't do splice.  I think, rather than
> > > making nfsd select SPLICE_SYSCALL, that it would suffice to change the
> > > "rqstp->rq_splice_ok = true;" in svc_process_common (net/sunrpc/svc.c)
> > > to:
> > > 
> > > rqstp->rq_splice_ok = IS_ENABLED(CONFIG_SPLICE_SYSCALL);
> > > 
> > > Then nfsd should simply *always* fall back to its non-splice support.
> > > 
> > 
> > I'd probably prefer the above, actually. We have to keep supporting
> > non-splice enabled fs' for the forseeable future, so we may as well
> > allow people to run nfsd in such configurations. It could even be
> > useful for testing the non-splice-enabled codepaths.
> 
> Good point!
> 
> - Josh Triplett

I'll add this to svc_process_common. I can squash this into PATCH 3, which is
where the syscalls can be compiled out. The log entry may however get a little
crowded and multi-functional.

Should I keep this as a separate patch?

^ permalink raw reply

* Re: [PATCH 07/17] new helpers: skb_copy_datagram_from_iter() and zerocopy_sg_from_iter()
From: Al Viro @ 2014-11-24 10:03 UTC (permalink / raw)
  To: Jason Wang
  Cc: Ben Hutchings, David Miller, torvalds, netdev, linux-kernel,
	target-devel, nab, hch
In-Reply-To: <5472C366.8020905@redhat.com>

On Mon, Nov 24, 2014 at 01:34:30PM +0800, Jason Wang wrote:
> >> +		copied = iov_iter_get_pages(from, pages, ~0U, MAX_SKB_FRAGS, &start);

> > Why is this condition needed, given we told iov_iter_get_pages() to
> > limit to MAX_SKB_FRAGS pages?
> 
> We don't want to send truncated packets and there's no other way to put
> those pages since it was not in the frag array.

No, his point is that it could never happen.  It could, actually - what's
confusing here (and that's inherited from zerocopy_from_iovec()) is
that 'i' is a lousy name for that variable.  It's actually "how many fragments
have we already put there?" and it is not reset when we go into the next
iteration of outer loop.

FWIW, I've just renamed it into 'frag', put
	if (frag == MAX_SKB_FRAGS)
		return -EMSGSIZE;
*before* iov_iter_get_pages(), passing MAX_SKB_FRAGS - frag as the
limit on number of pages in that call.  Voila - logics with put_page()
disappears and the inner loop is less obfuscated.

There was another bug in that function - iov_iter_get_pages() does *not*
advance the iterator; the caller needs to do iov_iter_advance() itself.
Also fixed...

^ permalink raw reply

* RE: [RFC] situation with csum_and_copy_... API
From: David Laight @ 2014-11-24 10:03 UTC (permalink / raw)
  To: 'Al Viro'
  Cc: Eric Dumazet, David Miller, torvalds@linux-foundation.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	target-devel@vger.kernel.org, Nicholas A. Bellinger,
	Christoph Hellwig
In-Reply-To: <20141121193911.GU7996@ZenIV.linux.org.uk>

From: Al Viro
> On Fri, Nov 21, 2014 at 05:42:55PM +0000, David Laight wrote:
> 
> > Callers of kernel_send/recvmsg() could easily be using a wrapper
> > function that creates the 'msghdr'.
> > When the want to send the remaining part of a buffer the old iterator
> > will no longer be available - just the original iov and the required offset.
> 
> Er...  So why not copy a struct iov_iter to/from msg->msg_iter, then?
> It's not as it had been particulary large - 5 words isn't much...
> 
> I'm not at all sure that _anything_ has valid reasons for draining iovecs.
> Maintaining a struct iov_iter and modifying it is easy and actually faster...
> 
> Right now the main examples outside of net/* are due to unfortunate
> limitations of ->sendmsg() - until now it had no way to be told that
> desired data starts at offset.  With ->msg_iter it obviously becomes
> possible...

It may well be easier for code that only has to run in a new kernel.
But for code that has run in old kernels as well you still need
to modify the iov[].

This is also true of userspace - there is no way of completing
a partial transfer without modifying the iov[] to allow for the
partial transfer.

Note that I'm not suggesting that any of the 'write' functions
should ever modify an iov[].

	David

^ permalink raw reply

* [PATCH net-next] tipc: fix sparse warnings in new nl api
From: richard.alpe @ 2014-11-24 10:10 UTC (permalink / raw)
  To: netdev; +Cc: Richard Alpe

From: Richard Alpe <richard.alpe@ericsson.com>

Fix sparse warnings about non-static declaration of static functions
in the new tipc netlink API.

Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
---
 net/tipc/bcast.c      |  3 ++-
 net/tipc/bearer.c     |  6 ++++--
 net/tipc/link.c       | 10 ++++++----
 net/tipc/name_table.c | 13 +++++++------
 net/tipc/node.c       |  2 +-
 net/tipc/socket.c     | 16 +++++++++-------
 6 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index dcf3589..556b26a 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -767,7 +767,8 @@ void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
 	tipc_bclink_unlock();
 }
 
-int __tipc_nl_add_bc_link_stat(struct sk_buff *skb, struct tipc_stats *stats)
+static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb,
+				      struct tipc_stats *stats)
 {
 	int i;
 	struct nlattr *nest;
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 5f6f323..463db5b 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -647,7 +647,8 @@ void tipc_bearer_stop(void)
 }
 
 /* Caller should hold rtnl_lock to protect the bearer */
-int __tipc_nl_add_bearer(struct tipc_nl_msg *msg, struct tipc_bearer *bearer)
+static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,
+				struct tipc_bearer *bearer)
 {
 	void *hdr;
 	struct nlattr *attrs;
@@ -905,7 +906,8 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-int __tipc_nl_add_media(struct tipc_nl_msg *msg, struct tipc_media *media)
+static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
+			       struct tipc_media *media)
 {
 	void *hdr;
 	struct nlattr *attrs;
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 629e8cf..4738cb1 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2514,7 +2514,8 @@ out:
 
 	return res;
 }
-int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s)
+
+static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s)
 {
 	int i;
 	struct nlattr *stats;
@@ -2580,7 +2581,7 @@ msg_full:
 }
 
 /* Caller should hold appropriate locks to protect the link */
-int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link)
+static int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link)
 {
 	int err;
 	void *hdr;
@@ -2649,8 +2650,9 @@ msg_full:
 }
 
 /* Caller should hold node lock  */
-int __tipc_nl_add_node_links(struct tipc_nl_msg *msg, struct tipc_node *node,
-			     u32 *prev_link)
+static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,
+				    struct tipc_node *node,
+				    u32 *prev_link)
 {
 	u32 i;
 	int err;
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 30ca8e0..7cfb7a4 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -1002,8 +1002,9 @@ void tipc_nametbl_stop(void)
 	write_unlock_bh(&tipc_nametbl_lock);
 }
 
-int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg, struct name_seq *seq,
-				 struct sub_seq *sseq, u32 *last_publ)
+static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
+					struct name_seq *seq,
+					struct sub_seq *sseq, u32 *last_publ)
 {
 	void *hdr;
 	struct nlattr *attrs;
@@ -1071,8 +1072,8 @@ msg_full:
 	return -EMSGSIZE;
 }
 
-int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
-			  u32 *last_lower, u32 *last_publ)
+static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
+				 u32 *last_lower, u32 *last_publ)
 {
 	struct sub_seq *sseq;
 	struct sub_seq *sseq_start;
@@ -1098,8 +1099,8 @@ int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
 	return 0;
 }
 
-int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type, u32 *last_lower,
-		       u32 *last_publ)
+static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
+			      u32 *last_lower, u32 *last_publ)
 {
 	struct hlist_head *seq_head;
 	struct name_seq *seq;
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 72a75d4..82e5edd 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -609,7 +609,7 @@ void tipc_node_unlock(struct tipc_node *node)
 }
 
 /* Caller should hold node lock for the passed node */
-int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
+static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
 {
 	void *hdr;
 	struct nlattr *attrs;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index e918091..6aa8c6a 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2811,7 +2811,7 @@ void tipc_socket_stop(void)
 }
 
 /* Caller should hold socket lock for the passed tipc socket. */
-int __tipc_nl_add_sk_con(struct sk_buff *skb, struct tipc_sock *tsk)
+static int __tipc_nl_add_sk_con(struct sk_buff *skb, struct tipc_sock *tsk)
 {
 	u32 peer_node;
 	u32 peer_port;
@@ -2846,8 +2846,8 @@ msg_full:
 }
 
 /* Caller should hold socket lock for the passed tipc socket. */
-int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
-		     struct tipc_sock *tsk)
+static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
+			    struct tipc_sock *tsk)
 {
 	int err;
 	void *hdr;
@@ -2912,8 +2912,9 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
 }
 
 /* Caller should hold socket lock for the passed tipc socket. */
-int __tipc_nl_add_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
-			  struct publication *publ)
+static int __tipc_nl_add_sk_publ(struct sk_buff *skb,
+				 struct netlink_callback *cb,
+				 struct publication *publ)
 {
 	void *hdr;
 	struct nlattr *attrs;
@@ -2950,8 +2951,9 @@ msg_cancel:
 }
 
 /* Caller should hold socket lock for the passed tipc socket. */
-int __tipc_nl_list_sk_publ(struct sk_buff *skb, struct netlink_callback *cb,
-			   struct tipc_sock *tsk, u32 *last_publ)
+static int __tipc_nl_list_sk_publ(struct sk_buff *skb,
+				  struct netlink_callback *cb,
+				  struct tipc_sock *tsk, u32 *last_publ)
 {
 	int err;
 	struct publication *p;
-- 
2.1.1

^ permalink raw reply related

* Re: [PATCH 08/17] {macvtap,tun}_get_user(): switch to iov_iter
From: Al Viro @ 2014-11-24 10:15 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
	hch
In-Reply-To: <1416788862.7215.65.camel@decadent.org.uk>

On Mon, Nov 24, 2014 at 12:27:42AM +0000, Ben Hutchings wrote:
> >  		copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN;
> >  		if (copylen > good_linear)
> >  			copylen = good_linear;
> >  		linear = copylen;
> > -		if (iov_pages(iv, vnet_hdr_len + copylen, count)
> > -		    <= MAX_SKB_FRAGS)
> > +		i = *from;
> > +		iov_iter_advance(&i, copylen);
> > +		if (iov_iter_npages(&i, INT_MAX) <= MAX_SKB_FRAGS)
> 
> The maxpages argument should be MAX_SKB_FRAGS + 1 as we don't need the
> exact number.

In principle, that's true, but...  Do we really care?  It only buys you
anything if you have a monstrously fragmented iovec.  And if you end up
spending too considerable amount of time in that loop in iov_iter_npages,
you are by definition on the slow path - it *will* fail, since we do not
even try to merge adjacent iovec segments.  Never had...

^ permalink raw reply

* Re: [PATCH 17/17] rds: switch rds_message_copy_from_user() to iov_iter
From: Al Viro @ 2014-11-24 10:17 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
	hch
In-Reply-To: <1416794418.7215.74.camel@decadent.org.uk>

On Mon, Nov 24, 2014 at 02:00:18AM +0000, Ben Hutchings wrote:
> On Sat, 2014-11-22 at 04:39 +0000, Al Viro wrote:
> [...]
> > -		ret = rds_page_copy_from_user(sg_page(sg), sg->offset + sg_off,
> > -					      iov->iov_base + iov_off,
> > -					      to_copy);
> [...]
> 
> It looks like rds_page_copy{,_from,_to}_user() are all unused after this
> change, so you could delete them.

Maybe.  Or maybe add a saner wrapper for rds_page_copy_from_user()...  Separate
story, anyway.

^ permalink raw reply

* Re: [RFC PATCH 0/4] switch device: offload policy attributes
From: Scott Feldman @ 2014-11-24 10:18 UTC (permalink / raw)
  To: Roopa Prabhu
  Cc: Jiří Pírko, Jamal Hadi Salim, Benjamin LaHaise,
	Thomas Graf, john.fastabend, stephen, John Linville, nhorman,
	Nicolas Dichtel, vyasevic, Florian Fainelli, buytenh, Aviad Raveh,
	Netdev, David S. Miller, shrijeet, Andy Gospodarek
In-Reply-To: <1416610170-21224-1-git-send-email-roopa@cumulusnetworks.com>

Hi Roopa,

I have a patch pending against Jiri's v2 that's uses existing
ndo_bridge_setlink/getlink to push policy settings down to port driver
for controlling HW offload.  I had to make a few tweaks, but for the
most part setlink/getlink already has the master/self semantics so
users can set policy flags on bridge's SW version of the port (master)
or on the offloaded version of the port (self).  I added the new
hwmode option "swdev" to the existing "vepa"|"veb" choices.  When you
specify hwmode, SELF is set and the port driver's setlink get's
called.  Did you look at setlink/getlink?  It looks like the kernel
and iproute2 where going down this route of using setlink/getlink for
SELF policy, so I'm wondering if we need more?

On FDB entries, using master/self semantics that exist, it's clear
which are owned by offloaded device and which are owned by bridge.
The one missing annotation was a flag indicating FDB entry in bridge
was synced from device.  And a policy flag to turn on/off syncing from
the device.  The policy flag is just another IFLA_BRPORT flags passed
with setlink/getlink.

The setlink/getlink patch will go out in v3 once I finish testing it
and push it to Jiri.  Hopefully tomorrow.

-scott

On Fri, Nov 21, 2014 at 12:49 PM,  <roopa@cumulusnetworks.com> wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
>
> This series aims at introducing new policy attibutes/flags to enable
> selective offloading of kernel network objects.
> This is in the context of supporting switch devices in the linux kernel.
>
> Assumption:
>     - All kernel network objects (routes, neighs, bridges, bonds, vxlans)
>       can be offloaded (This is true today with a few exceptions maybe)
>
> policy points:
>     - By default all objects exist in software (kernel)
>     - Per object flag to add/del/show in kernel, hardware or both
>     - System global option to turn on/off offloads for all network objects.
>       This is for systems who want to turn offloading on for all network objects
>       by default. us :). Apps dont need to know about offloading in this
>       model. (TBD)
>
> Patches are based on jiri/sfeldma's rocker work.
>
> Apologize for the incomplete and untested code. This is a sample patch
>  to get some initial feedback.
>
> Roopa Prabhu (4):
>   rtnetlink: new flag NLM_F_HW_OFFLOAD to indicate kernel object
>     offload to hardware
>   netdev: new feature flag NETIF_F_HW_OFFLOAD to indicate netdev object
>     offload to hardware
>   swdevice: new generic op to set bridge port attr
>   bridge: make hw offload conditional on bridge and bridge port offload
>     flags
>
>  include/linux/netdev_features.h |    1 +
>  include/net/switchdev.h         |    8 ++++++-
>  include/uapi/linux/netlink.h    |    2 ++
>  net/bridge/br_netlink.c         |   50 +++++++++++++++++++++++++++++++--------
>  net/bridge/br_private.h         |    2 ++
>  net/bridge/br_stp.c             |    9 ++++---
>  net/bridge/br_stp_if.c          |    8 +++++--
>  net/core/rtnetlink.c            |    7 ++++++
>  net/switchdev/switchdev.c       |   17 +++++++++++++
>  9 files changed, 88 insertions(+), 16 deletions(-)
>
> --
> 1.7.10.4
>

^ permalink raw reply

* [PATCH] wireless/p54: Remove duplicated  net2280 header
From: Ricardo Ribalda Delgado @ 2014-11-24 10:19 UTC (permalink / raw)
  To: Christian Lamparter, John W. Linville, linux-kernel,
	linux-wireless, netdev
  Cc: Ricardo Ribalda Delgado

The usb gadget driver net2280 has exported a header file with the
register definition of the net2280 chip.

Remove the custom/duplicated header file in favor of that header file
in include/linux

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/net/wireless/p54/net2280.h | 451 -------------------------------------
 drivers/net/wireless/p54/p54usb.h  |  13 +-
 2 files changed, 12 insertions(+), 452 deletions(-)
 delete mode 100644 drivers/net/wireless/p54/net2280.h

diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h
deleted file mode 100644
index aedfaf2..0000000
--- a/drivers/net/wireless/p54/net2280.h
+++ /dev/null
@@ -1,451 +0,0 @@
-#ifndef NET2280_H
-#define NET2280_H
-/*
- * NetChip 2280 high/full speed USB device controller.
- * Unlike many such controllers, this one talks PCI.
- */
-
-/*
- * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
- * Copyright (C) 2003 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* NET2280 MEMORY MAPPED REGISTERS
- *
- * The register layout came from the chip documentation, and the bit
- * number definitions were extracted from chip specification.
- *
- * Use the shift operator ('<<') to build bit masks, with readl/writel
- * to access the registers through PCI.
- */
-
-/* main registers, BAR0 + 0x0000 */
-struct net2280_regs {
-	/* offset 0x0000 */
-	__le32			devinit;
-#define LOCAL_CLOCK_FREQUENCY					8
-#define FORCE_PCI_RESET						7
-#define PCI_ID							6
-#define PCI_ENABLE						5
-#define FIFO_SOFT_RESET						4
-#define CFG_SOFT_RESET						3
-#define PCI_SOFT_RESET						2
-#define USB_SOFT_RESET						1
-#define M8051_RESET						0
-	__le32			eectl;
-#define EEPROM_ADDRESS_WIDTH					23
-#define EEPROM_CHIP_SELECT_ACTIVE				22
-#define EEPROM_PRESENT						21
-#define EEPROM_VALID						20
-#define EEPROM_BUSY						19
-#define EEPROM_CHIP_SELECT_ENABLE				18
-#define EEPROM_BYTE_READ_START					17
-#define EEPROM_BYTE_WRITE_START					16
-#define EEPROM_READ_DATA					8
-#define EEPROM_WRITE_DATA					0
-	__le32			eeclkfreq;
-	u32			_unused0;
-	/* offset 0x0010 */
-
-	__le32			pciirqenb0;	/* interrupt PCI master ... */
-#define SETUP_PACKET_INTERRUPT_ENABLE				7
-#define ENDPOINT_F_INTERRUPT_ENABLE				6
-#define ENDPOINT_E_INTERRUPT_ENABLE				5
-#define ENDPOINT_D_INTERRUPT_ENABLE				4
-#define ENDPOINT_C_INTERRUPT_ENABLE				3
-#define ENDPOINT_B_INTERRUPT_ENABLE				2
-#define ENDPOINT_A_INTERRUPT_ENABLE				1
-#define ENDPOINT_0_INTERRUPT_ENABLE				0
-	__le32			pciirqenb1;
-#define PCI_INTERRUPT_ENABLE					31
-#define POWER_STATE_CHANGE_INTERRUPT_ENABLE			27
-#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE			26
-#define PCI_PARITY_ERROR_INTERRUPT_ENABLE			25
-#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE		20
-#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE		19
-#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE		18
-#define PCI_RETRY_ABORT_INTERRUPT_ENABLE			17
-#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE			16
-#define GPIO_INTERRUPT_ENABLE					13
-#define DMA_D_INTERRUPT_ENABLE					12
-#define DMA_C_INTERRUPT_ENABLE					11
-#define DMA_B_INTERRUPT_ENABLE					10
-#define DMA_A_INTERRUPT_ENABLE					9
-#define EEPROM_DONE_INTERRUPT_ENABLE				8
-#define VBUS_INTERRUPT_ENABLE					7
-#define CONTROL_STATUS_INTERRUPT_ENABLE				6
-#define ROOT_PORT_RESET_INTERRUPT_ENABLE			4
-#define SUSPEND_REQUEST_INTERRUPT_ENABLE			3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE			2
-#define RESUME_INTERRUPT_ENABLE					1
-#define SOF_INTERRUPT_ENABLE					0
-	__le32                  cpu_irqenb0;	/* ... or onboard 8051 */
-#define SETUP_PACKET_INTERRUPT_ENABLE				7
-#define ENDPOINT_F_INTERRUPT_ENABLE				6
-#define ENDPOINT_E_INTERRUPT_ENABLE				5
-#define ENDPOINT_D_INTERRUPT_ENABLE				4
-#define ENDPOINT_C_INTERRUPT_ENABLE				3
-#define ENDPOINT_B_INTERRUPT_ENABLE				2
-#define ENDPOINT_A_INTERRUPT_ENABLE				1
-#define ENDPOINT_0_INTERRUPT_ENABLE				0
-	__le32                  cpu_irqenb1;
-#define CPU_INTERRUPT_ENABLE					31
-#define POWER_STATE_CHANGE_INTERRUPT_ENABLE			27
-#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE			26
-#define PCI_PARITY_ERROR_INTERRUPT_ENABLE			25
-#define PCI_INTA_INTERRUPT_ENABLE				24
-#define PCI_PME_INTERRUPT_ENABLE				23
-#define PCI_SERR_INTERRUPT_ENABLE				22
-#define PCI_PERR_INTERRUPT_ENABLE				21
-#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE		20
-#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE		19
-#define PCI_RETRY_ABORT_INTERRUPT_ENABLE			17
-#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE			16
-#define GPIO_INTERRUPT_ENABLE					13
-#define DMA_D_INTERRUPT_ENABLE					12
-#define DMA_C_INTERRUPT_ENABLE					11
-#define DMA_B_INTERRUPT_ENABLE					10
-#define DMA_A_INTERRUPT_ENABLE					9
-#define EEPROM_DONE_INTERRUPT_ENABLE				8
-#define VBUS_INTERRUPT_ENABLE					7
-#define CONTROL_STATUS_INTERRUPT_ENABLE				6
-#define ROOT_PORT_RESET_INTERRUPT_ENABLE			4
-#define SUSPEND_REQUEST_INTERRUPT_ENABLE			3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE			2
-#define RESUME_INTERRUPT_ENABLE					1
-#define SOF_INTERRUPT_ENABLE					0
-
-	/* offset 0x0020 */
-	u32			_unused1;
-	__le32			usbirqenb1;
-#define USB_INTERRUPT_ENABLE					31
-#define POWER_STATE_CHANGE_INTERRUPT_ENABLE			27
-#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE			26
-#define PCI_PARITY_ERROR_INTERRUPT_ENABLE			25
-#define PCI_INTA_INTERRUPT_ENABLE				24
-#define PCI_PME_INTERRUPT_ENABLE				23
-#define PCI_SERR_INTERRUPT_ENABLE				22
-#define PCI_PERR_INTERRUPT_ENABLE				21
-#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE		20
-#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE		19
-#define PCI_RETRY_ABORT_INTERRUPT_ENABLE			17
-#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE			16
-#define GPIO_INTERRUPT_ENABLE					13
-#define DMA_D_INTERRUPT_ENABLE					12
-#define DMA_C_INTERRUPT_ENABLE					11
-#define DMA_B_INTERRUPT_ENABLE					10
-#define DMA_A_INTERRUPT_ENABLE					9
-#define EEPROM_DONE_INTERRUPT_ENABLE				8
-#define VBUS_INTERRUPT_ENABLE					7
-#define CONTROL_STATUS_INTERRUPT_ENABLE				6
-#define ROOT_PORT_RESET_INTERRUPT_ENABLE			4
-#define SUSPEND_REQUEST_INTERRUPT_ENABLE			3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE			2
-#define RESUME_INTERRUPT_ENABLE					1
-#define SOF_INTERRUPT_ENABLE					0
-	__le32			irqstat0;
-#define INTA_ASSERTED						12
-#define SETUP_PACKET_INTERRUPT					7
-#define ENDPOINT_F_INTERRUPT					6
-#define ENDPOINT_E_INTERRUPT					5
-#define ENDPOINT_D_INTERRUPT					4
-#define ENDPOINT_C_INTERRUPT					3
-#define ENDPOINT_B_INTERRUPT					2
-#define ENDPOINT_A_INTERRUPT					1
-#define ENDPOINT_0_INTERRUPT					0
-	__le32			irqstat1;
-#define POWER_STATE_CHANGE_INTERRUPT				27
-#define PCI_ARBITER_TIMEOUT_INTERRUPT				26
-#define PCI_PARITY_ERROR_INTERRUPT				25
-#define PCI_INTA_INTERRUPT					24
-#define PCI_PME_INTERRUPT					23
-#define PCI_SERR_INTERRUPT					22
-#define PCI_PERR_INTERRUPT					21
-#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT			20
-#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT			19
-#define PCI_RETRY_ABORT_INTERRUPT				17
-#define PCI_MASTER_CYCLE_DONE_INTERRUPT				16
-#define GPIO_INTERRUPT						13
-#define DMA_D_INTERRUPT						12
-#define DMA_C_INTERRUPT						11
-#define DMA_B_INTERRUPT						10
-#define DMA_A_INTERRUPT						9
-#define EEPROM_DONE_INTERRUPT					8
-#define VBUS_INTERRUPT						7
-#define CONTROL_STATUS_INTERRUPT				6
-#define ROOT_PORT_RESET_INTERRUPT				4
-#define SUSPEND_REQUEST_INTERRUPT				3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT			2
-#define RESUME_INTERRUPT					1
-#define SOF_INTERRUPT						0
-	/* offset 0x0030 */
-	__le32			idxaddr;
-	__le32			idxdata;
-	__le32			fifoctl;
-#define PCI_BASE2_RANGE						16
-#define IGNORE_FIFO_AVAILABILITY				3
-#define PCI_BASE2_SELECT					2
-#define FIFO_CONFIGURATION_SELECT				0
-	u32			_unused2;
-	/* offset 0x0040 */
-	__le32			memaddr;
-#define START							28
-#define DIRECTION						27
-#define FIFO_DIAGNOSTIC_SELECT					24
-#define MEMORY_ADDRESS						0
-	__le32			memdata0;
-	__le32			memdata1;
-	u32			_unused3;
-	/* offset 0x0050 */
-	__le32			gpioctl;
-#define GPIO3_LED_SELECT					12
-#define GPIO3_INTERRUPT_ENABLE					11
-#define GPIO2_INTERRUPT_ENABLE					10
-#define GPIO1_INTERRUPT_ENABLE					9
-#define GPIO0_INTERRUPT_ENABLE					8
-#define GPIO3_OUTPUT_ENABLE					7
-#define GPIO2_OUTPUT_ENABLE					6
-#define GPIO1_OUTPUT_ENABLE					5
-#define GPIO0_OUTPUT_ENABLE					4
-#define GPIO3_DATA						3
-#define GPIO2_DATA						2
-#define GPIO1_DATA						1
-#define GPIO0_DATA						0
-	__le32			gpiostat;
-#define GPIO3_INTERRUPT						3
-#define GPIO2_INTERRUPT						2
-#define GPIO1_INTERRUPT						1
-#define GPIO0_INTERRUPT						0
-} __packed;
-
-/* usb control, BAR0 + 0x0080 */
-struct net2280_usb_regs {
-	/* offset 0x0080 */
-	__le32			stdrsp;
-#define STALL_UNSUPPORTED_REQUESTS				31
-#define SET_TEST_MODE						16
-#define GET_OTHER_SPEED_CONFIGURATION				15
-#define GET_DEVICE_QUALIFIER					14
-#define SET_ADDRESS						13
-#define ENDPOINT_SET_CLEAR_HALT					12
-#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP			11
-#define GET_STRING_DESCRIPTOR_2					10
-#define GET_STRING_DESCRIPTOR_1					9
-#define GET_STRING_DESCRIPTOR_0					8
-#define GET_SET_INTERFACE					6
-#define GET_SET_CONFIGURATION					5
-#define GET_CONFIGURATION_DESCRIPTOR				4
-#define GET_DEVICE_DESCRIPTOR					3
-#define GET_ENDPOINT_STATUS					2
-#define GET_INTERFACE_STATUS					1
-#define GET_DEVICE_STATUS					0
-	__le32			prodvendid;
-#define     PRODUCT_ID						16
-#define     VENDOR_ID						0
-	__le32			relnum;
-	__le32			usbctl;
-#define SERIAL_NUMBER_INDEX					16
-#define PRODUCT_ID_STRING_ENABLE				13
-#define VENDOR_ID_STRING_ENABLE					12
-#define USB_ROOT_PORT_WAKEUP_ENABLE				11
-#define VBUS_PIN						10
-#define TIMED_DISCONNECT					9
-#define SUSPEND_IMMEDIATELY					7
-#define SELF_POWERED_USB_DEVICE					6
-#define REMOTE_WAKEUP_SUPPORT					5
-#define PME_POLARITY						4
-#define USB_DETECT_ENABLE					3
-#define PME_WAKEUP_ENABLE					2
-#define DEVICE_REMOTE_WAKEUP_ENABLE				1
-#define SELF_POWERED_STATUS					0
-	/* offset 0x0090 */
-	__le32			usbstat;
-#define HIGH_SPEED						7
-#define FULL_SPEED						6
-#define GENERATE_RESUME						5
-#define GENERATE_DEVICE_REMOTE_WAKEUP				4
-	__le32			xcvrdiag;
-#define FORCE_HIGH_SPEED_MODE					31
-#define FORCE_FULL_SPEED_MODE					30
-#define USB_TEST_MODE						24
-#define LINE_STATE						16
-#define TRANSCEIVER_OPERATION_MODE				2
-#define TRANSCEIVER_SELECT					1
-#define TERMINATION_SELECT					0
-	__le32			setup0123;
-	__le32			setup4567;
-	/* offset 0x0090 */
-	u32			_unused0;
-	__le32			ouraddr;
-#define FORCE_IMMEDIATE						7
-#define OUR_USB_ADDRESS						0
-	__le32			ourconfig;
-} __packed;
-
-/* pci control, BAR0 + 0x0100 */
-struct net2280_pci_regs {
-	/* offset 0x0100 */
-	__le32			pcimstctl;
-#define PCI_ARBITER_PARK_SELECT					13
-#define PCI_MULTI LEVEL_ARBITER					12
-#define PCI_RETRY_ABORT_ENABLE					11
-#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE			10
-#define DMA_READ_MULTIPLE_ENABLE				9
-#define DMA_READ_LINE_ENABLE					8
-#define PCI_MASTER_COMMAND_SELECT				6
-#define		MEM_READ_OR_WRITE				0
-#define		IO_READ_OR_WRITE				1
-#define		CFG_READ_OR_WRITE				2
-#define PCI_MASTER_START					5
-#define PCI_MASTER_READ_WRITE					4
-#define		PCI_MASTER_WRITE				0
-#define		PCI_MASTER_READ					1
-#define PCI_MASTER_BYTE_WRITE_ENABLES				0
-	__le32			pcimstaddr;
-	__le32			pcimstdata;
-	__le32			pcimststat;
-#define PCI_ARBITER_CLEAR					2
-#define PCI_EXTERNAL_ARBITER					1
-#define PCI_HOST_MODE						0
-} __packed;
-
-/* dma control, BAR0 + 0x0180 ... array of four structs like this,
- * for channels 0..3.  see also struct net2280_dma:  descriptor
- * that can be loaded into some of these registers.
- */
-struct net2280_dma_regs {	/* [11.7] */
-	/* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */
-	__le32			dmactl;
-#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE		25
-#define DMA_CLEAR_COUNT_ENABLE					21
-#define DESCRIPTOR_POLLING_RATE					19
-#define		POLL_CONTINUOUS					0
-#define		POLL_1_USEC					1
-#define		POLL_100_USEC					2
-#define		POLL_1_MSEC					3
-#define DMA_VALID_BIT_POLLING_ENABLE				18
-#define DMA_VALID_BIT_ENABLE					17
-#define DMA_SCATTER_GATHER_ENABLE				16
-#define DMA_OUT_AUTO_START_ENABLE				4
-#define DMA_PREEMPT_ENABLE					3
-#define DMA_FIFO_VALIDATE					2
-#define DMA_ENABLE						1
-#define DMA_ADDRESS_HOLD					0
-	__le32			dmastat;
-#define DMA_SCATTER_GATHER_DONE_INTERRUPT			25
-#define DMA_TRANSACTION_DONE_INTERRUPT				24
-#define DMA_ABORT						1
-#define DMA_START						0
-	u32			_unused0[2];
-	/* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */
-	__le32                  dmacount;
-#define VALID_BIT						31
-#define DMA_DIRECTION						30
-#define DMA_DONE_INTERRUPT_ENABLE				29
-#define END_OF_CHAIN						28
-#define DMA_BYTE_COUNT_MASK					((1<<24)-1)
-#define DMA_BYTE_COUNT						0
-	__le32			dmaaddr;
-	__le32			dmadesc;
-	u32			_unused1;
-} __packed;
-
-/* dedicated endpoint registers, BAR0 + 0x0200 */
-
-struct net2280_dep_regs {	/* [11.8] */
-	/* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */
-	__le32			dep_cfg;
-	/* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
-	__le32			dep_rsp;
-	u32			_unused[2];
-} __packed;
-
-/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
- * like this, for ep0 then the configurable endpoints A..F
- * ep0 reserved for control; E and F have only 64 bytes of fifo
- */
-struct net2280_ep_regs {	/* [11.9] */
-	/* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */
-	__le32			ep_cfg;
-#define ENDPOINT_BYTE_COUNT					16
-#define ENDPOINT_ENABLE						10
-#define ENDPOINT_TYPE						8
-#define ENDPOINT_DIRECTION					7
-#define ENDPOINT_NUMBER						0
-	__le32			ep_rsp;
-#define SET_NAK_OUT_PACKETS					15
-#define SET_EP_HIDE_STATUS_PHASE				14
-#define SET_EP_FORCE_CRC_ERROR					13
-#define SET_INTERRUPT_MODE					12
-#define SET_CONTROL_STATUS_PHASE_HANDSHAKE			11
-#define SET_NAK_OUT_PACKETS_MODE				10
-#define SET_ENDPOINT_TOGGLE					9
-#define SET_ENDPOINT_HALT					8
-#define CLEAR_NAK_OUT_PACKETS					7
-#define CLEAR_EP_HIDE_STATUS_PHASE				6
-#define CLEAR_EP_FORCE_CRC_ERROR				5
-#define CLEAR_INTERRUPT_MODE					4
-#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE			3
-#define CLEAR_NAK_OUT_PACKETS_MODE				2
-#define CLEAR_ENDPOINT_TOGGLE					1
-#define CLEAR_ENDPOINT_HALT					0
-	__le32			ep_irqenb;
-#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE			6
-#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE		5
-#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE			3
-#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE		2
-#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE			1
-#define DATA_IN_TOKEN_INTERRUPT_ENABLE				0
-	__le32			ep_stat;
-#define FIFO_VALID_COUNT					24
-#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID			22
-#define TIMEOUT							21
-#define USB_STALL_SENT						20
-#define USB_IN_NAK_SENT						19
-#define USB_IN_ACK_RCVD						18
-#define USB_OUT_PING_NAK_SENT					17
-#define USB_OUT_ACK_SENT					16
-#define FIFO_OVERFLOW						13
-#define FIFO_UNDERFLOW						12
-#define FIFO_FULL						11
-#define FIFO_EMPTY						10
-#define FIFO_FLUSH						9
-#define SHORT_PACKET_OUT_DONE_INTERRUPT				6
-#define SHORT_PACKET_TRANSFERRED_INTERRUPT			5
-#define NAK_OUT_PACKETS						4
-#define DATA_PACKET_RECEIVED_INTERRUPT				3
-#define DATA_PACKET_TRANSMITTED_INTERRUPT			2
-#define DATA_OUT_PING_TOKEN_INTERRUPT				1
-#define DATA_IN_TOKEN_INTERRUPT					0
-	/* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */
-	__le32			ep_avail;
-	__le32			ep_data;
-	u32			_unused0[2];
-} __packed;
-
-struct net2280_reg_write {
-	__le16 port;
-	__le32 addr;
-	__le32 val;
-} __packed;
-
-struct net2280_reg_read {
-	__le16 port;
-	__le32 addr;
-} __packed;
-#endif /* NET2280_H */
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index d273be7..a5f5f0f 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -16,7 +16,7 @@
 
 /* for isl3886 register definitions used on ver 1 devices */
 #include "p54pci.h"
-#include "net2280.h"
+#include <linux/usb/net2280.h>
 
 /* pci */
 #define NET2280_BASE		0x10000000
@@ -93,6 +93,17 @@ enum net2280_op_type {
 	NET2280_DEV_CFG_U16	= 0x0883
 };
 
+struct net2280_reg_write {
+	__le16 port;
+	__le32 addr;
+	__le32 val;
+} __packed;
+
+struct net2280_reg_read {
+	__le16 port;
+	__le32 addr;
+} __packed;
+
 #define P54U_FW_BLOCK 2048
 
 #define X2_SIGNATURE "x2  "
-- 
2.1.3

^ permalink raw reply related

* [PATCH net] ipv6: gre: fix wrong skb->protocol in WCCP
From: Daniel Borkmann @ 2014-11-24 10:25 UTC (permalink / raw)
  To: davem; +Cc: hannes, netdev, Yuri Chislov, Dmitry Kozlov

From: Yuri Chislov <yuri.chislov@gmail.com>

When using GRE redirection in WCCP, it sets the wrong skb->protocol,
that is, ETH_P_IP instead of ETH_P_IPV6 for the encapuslated traffic.

Fixes: c12b395a4664 ("gre: Support GRE over IPv6")
Cc: Dmitry Kozlov <xeb@mail.ru>
Signed-off-by: Yuri Chislov <yuri.chislov@gmail.com>
Tested-by: Yuri Chislov <yuri.chislov@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
 Also checked back with Dmitry, it was a copy-paste error from the
 IPv4 implementation.

 net/ipv6/ip6_gre.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 4564e1f..0e32d2e 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -502,11 +502,11 @@ static int ip6gre_rcv(struct sk_buff *skb)
 
 		skb->protocol = gre_proto;
 		/* WCCP version 1 and 2 protocol decoding.
-		 * - Change protocol to IP
+		 * - Change protocol to IPv6
 		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
 		 */
 		if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
-			skb->protocol = htons(ETH_P_IP);
+			skb->protocol = htons(ETH_P_IPV6);
 			if ((*(h + offset) & 0xF0) != 0x40)
 				offset += 4;
 		}
-- 
1.7.11.7

^ permalink raw reply related

* RE: [RFC] situation with csum_and_copy_... API
From: David Laight @ 2014-11-24 10:27 UTC (permalink / raw)
  To: 'Al Viro', Linus Torvalds
  Cc: David Miller, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, target-devel@vger.kernel.org,
	Nicholas A. Bellinger, Christoph Hellwig, Eric Dumazet
In-Reply-To: <20141122032718.GA24457@ZenIV.linux.org.uk>

From: Al Viro
> On Fri, Nov 21, 2014 at 08:49:56AM +0000, Al Viro wrote:
> 
> > Overall, I think I have the whole series plotted in enough details to be
> > reasonably certain we can pull it off.  Right now I'm dealing with
> > mm/iov_iter.c stuff; the amount of boilerplate source is already high enough
> > and with those extra primitives it'll get really unpleasant.
> >
> > What we need there is something templates-like, as much as I hate C++, and
> > I'm still not happy with what I have at the moment...  Hopefully I'll get
> > that in more or less tolerable form today.
> 
> Folks, I would really like comments on the patch below.  It's an attempt
> to reduce the amount of boilerplate code in mm/iov_iter.c; no new primitives
> added, just trying to reduce the amount of duplication in there.  I'm not
> too fond of the way it currently looks, to put it mildly.  It seems to
> work, it's reasonably straightforward and it even generates slightly better
> code than before, but I would _very_ welcome any tricks that would allow to
> make it not so tasteless.  I like the effect on line count (+124-358), but...
> 
> It defines two iterators (for iovec-backed and bvec-backed ones) and converts
> a bunch of primitives to those.  The last argument is an expression evaluated
> for a bunch of ranges; for bvec one it's void, for iovec - size_t; if it
> evaluates to non-0, we treat it as read/write/whatever short by that many
> bytes and do not proceed any further.
> 
> Any suggestions are welcome.
> 
> diff --git a/mm/iov_iter.c b/mm/iov_iter.c
> index eafcf60..611af2bd 100644
> --- a/mm/iov_iter.c
> +++ b/mm/iov_iter.c
> @@ -4,11 +4,75 @@
>  #include <linux/slab.h>
>  #include <linux/vmalloc.h>
> 
> +#define iterate_iovec(i, n, buf, len, move, STEP) {	\
> +	const struct iovec *iov = i->iov;		\
> +	size_t skip = i->iov_offset;			\
> +	size_t left;					\
> +	size_t wanted = n;				\

All these variable names probably want (at least one) _ prefix
just in case they match the names of arguments.

> +	buf = iov->iov_base + skip;			\
> +	len = min(n, iov->iov_len - skip);		\

You are assigning to parameters, this can get confusing.
Unless these are return values this probably doesn't make sense.
Might be better to 'pass by reference', the generated code is
likely to be the same - but it is clearer to the reader.

> +	left = STEP;					\
> +	len -= left;					\
> +	skip += len;					\
> +	n -= len;					\

Again, a parameter is modified.

> +	while (unlikely(!left && n)) {			\
> +		iov++;					\
> +		buf = iov->iov_base;			\
> +		len = min(n, iov->iov_len);		\
> +		left = STEP;				\
> +		len -= left;				\
> +		skip = len;				\
> +		n -= len;				\
> +	}						\
> +	n = wanted - n;					\
> +	if (move) {					\
> +		if (skip == iov->iov_len) {		\
> +			iov++;				\
> +			skip = 0;			\
> +		}					\
> +		i->count -= n;				\
> +		i->nr_segs -= iov - i->iov;		\
> +		i->iov = iov;				\
> +		i->iov_offset = skip;			\
> +	}						\
> +}
...
> +	iterate_iovec(i, bytes, buf, len, true,
> +			__copy_to_user(buf, (from += len) - len, len))
> +	return bytes;

Using 'buf' and 'len' in __copy_to_user() is very non-obvious.
It might be better if they were fixed names, maybe _ioiter_buf and _ioiter_len.

If this code can use the gcc extension that allows #defines that contain {}
to return values, the it would be better as:

	bytes_left = iterate_iovec(i, bytes, true,
		__copy_to_user(_ioiter_buf, (from += _ioiter_len) - _ioiter_len,
			_ioiter_len);
	return bytes_left;

Possibly also two wrapper #defines that supply the true/false parameter.

	David

^ permalink raw reply


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