* Re: [PATCH net-next v2] ipv6: coding style improvements (remove assignment in if statements)
From: David Miller @ 2014-11-24 2:01 UTC (permalink / raw)
To: ipm; +Cc: netdev
In-Reply-To: <1416778123-5803-1-git-send-email-ipm@chirality.org.uk>
From: Ian Morris <ipm@chirality.org.uk>
Date: Sun, 23 Nov 2014 21:28:43 +0000
> This change has no functional impact and simply addresses some coding
> style issues detected by checkpatch. Specifically this change
> adjusts "if" statements which also include the assignment of a
> variable.
>
> No changes to the resultant object files result as determined by objdiff.
>
> Signed-off-by: Ian Morris <ipm@chirality.org.uk>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 17/17] rds: switch rds_message_copy_from_user() to iov_iter
From: Ben Hutchings @ 2014-11-24 2:00 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <20141122043920.GQ30478@ZenIV.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 412 bytes --]
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.
Ben.
--
Ben Hutchings
Absolutum obsoletum. (If it works, it's out of date.) - Stafford Beer
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ permalink raw reply
* Re: [PATCH net-next v3] ipvlan: Initial check-in of the IPVLAN driver.
From: David Miller @ 2014-11-24 2:00 UTC (permalink / raw)
To: maheshb; +Cc: netdev, edumazet, maze, chavey, thockin, brandon.philips, xemul
In-Reply-To: <1416791954-6445-1-git-send-email-maheshb@google.com>
From: Mahesh Bandewar <maheshb@google.com>
Date: Sun, 23 Nov 2014 17:19:14 -0800
> +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;
Please put an empty line between variable declarations and code.
> +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;
> +}
Likewise.
> + } else if (addr_type == IPVL_ICMPV6) {
> + struct nd_msg *ndmh;
> + struct in6_addr *i6addr;
> + ndmh = (struct nd_msg *)lyr3h;
Likewise.
> + if (ether_addr_equal(eth->h_dest, eth->h_source)) {
> + netif_dbg(ipvlan, pktdata, dev,
> + "Comm betn 2 virt devs PROT=%x\n",
> + ntohs(skb->protocol));
> + if ((lyr3h = ipvlan_get_L3_hdr(skb, &addr_type)) == NULL)
> + goto to_default;
Please don't mix assignments and if() statement tests, put the
assignment by itself first, then test the variable.
Althought I'm not fundamentally against goto statements, it
doesn't help in any way here, and this code reads must easier
as:
if (lyr3h) {
addr = ipvlan_addr_lookup(...);
if (addr)
return ipvlan_rcv_frame(...);
}
> + /* No matching ipvlan dev! Must be on the Physical device */
> +to_default:
And then this label and even the comment above it can just be
deleted.
> + } else if (is_multicast_ether_addr(eth->h_dest)) {
> + u8 ip_summed = skb->ip_summed;
> + /* Packet needs to be multicast-ed. */
> + skb->ip_summed = CHECKSUM_UNNECESSARY;
Empty line between variable declarations and code, please.
And I think because we're testing against a mutlicast address,
you don't have to explicitly state that this is "the multicast
code path."
Use comments when it truly adds information, rather than basically
restating what the code is already explicitly saying to the reader.
Most of your comments in this driver just recap the code statements
in one way or another.
> +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 */
> + BUG();
Only use BUG statements when the kernel cannot continue operating
safely. Just because your own personal assertion is violated doesn't
mean the whole machine needs to be taken down.
Free the packet and emit a log message (perhaps with WARN()).
> + if ((lyr3h = ipvlan_get_L3_hdr(skb, &addr_type)) == NULL)
> + return true;
Change this to:
lyr3h = ipvlan_get_L3_hdr(...);
if (!lyr3h)
return true;
> +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)
> + goto out;
> +
> + 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 */
> + BUG();
Again, use WARN() not BUG().
> + if ((port = kzalloc(sizeof(struct ipvl_port), GFP_KERNEL)) == NULL)
> + return -ENOMEM;
Change this to:
port = kzalloc(sizeof(struct ipvl_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
> + list_for_each_entry(addr, &ipvlan->addrs, anode) {
> + ipvlan_ht_addr_add(ipvlan, addr);
> + }
Single line basic blocks do not require enclosing braces, please
remove them.
> + list_for_each_entry(addr, &ipvlan->addrs, anode) {
> + ipvlan_ht_addr_del(addr, !dev->dismantle);
> + }
Likewise.
> + struct ipvl_dev *ipvlan = netdev_priv(dev);
> + return features & (ipvlan->sfeatures | ~IPVLAN_FEATURES);
Empty line between local variable declarations and code.
> + if (set && !test_bit(hashbit, ipvlan->mac_filters)) {
> + /* Set broadcast hash-bit (for IPv4) */
> + __set_bit(hashbit, ipvlan->mac_filters);
> + } else if (!set && test_bit(hashbit, ipvlan->mac_filters)) {
> + /* Reset broadcast hash-bit */
> + __clear_bit(hashbit, ipvlan->mac_filters);
> + }
Comments are just restating the code, remove them. And then these
basic blocks are single line and thus you can remove all of the
braces as well.
> + netdev_for_each_mc_addr(ha, dev) {
> + __set_bit(ipvlan_mac_hash(ha->addr), mc_filters);
> + }
Single line basic block, toss the curly braces.
> + } while(u64_stats_fetch_retry_irq(&pcptr->syncp, strt));
Space needed between 'while' and the openning parenthesis.
> + const struct ipvl_dev *ipvlan = netdev_priv(dev);
> + return __ethtool_get_settings(ipvlan->phy_dev, cmd);
Empty line between variable declarations and code.
> + if (data && data[IFLA_IPVLAN_MODE]) {
> + u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
> + ipvlan_set_port_mode(port, nmode);
> + }
Likewise.
> + list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
> + ipvlan_adjust_mtu(ipvlan, dev);
> + }
Single line basic block doesn't need curly braces, please remove.
> + if ((addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC)) == NULL)
> + return -ENOMEM;
Change this to:
addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC);
if (!addr)
return -ENOMEM;
> + if ((addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true)) ==NULL)
> + return;
Same kind of transformation needed here.
> + /* Delete from the hash-table */
> + ipvlan_ht_addr_del(addr, true);
Comment just restates the code, remove.
> + /* Delete from the logical's addr list */
> + list_del_rcu(&addr->anode);
Likewise.
> + if ((addr= ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false)) ==NULL)
> + return;
This really looks terrible, bad spacing and combining an assignment
with an if() test. After reading the rest of my feedback above you
should know what to do with this.
Finally, please think seriously about all of your *_dbg() logging in
this driver. Does it really have true value after initial driver
development and debug? They take up a significant amount of lines
in the driver, and make it seem bigger than it really is.
Thanks.
^ permalink raw reply
* Re: [PATCH net-net 0/4] Increase the limit of tuntap queues
From: David Miller @ 2014-11-24 1:23 UTC (permalink / raw)
To: mst
Cc: pagupta, linux-kernel, netdev, jasowang, dgibson, vfalico,
edumazet, vyasevic, hkchu, wuzhy, xemul, therbert, bhutchings,
xii, stephen, jiri, sergei.shtylyov
In-Reply-To: <20141123203032.GA6286@redhat.com>
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.
^ permalink raw reply
* [PATCH net-next v3] ipvlan: Initial check-in of the IPVLAN driver.
From: Mahesh Bandewar @ 2014-11-24 1:19 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 | 131 ++++++
drivers/net/ipvlan/ipvlan_core.c | 629 ++++++++++++++++++++++++++++
drivers/net/ipvlan/ipvlan_main.c | 815 ++++++++++++++++++++++++++++++++++++
include/linux/netdevice.h | 4 +
include/uapi/linux/if_link.h | 15 +
9 files changed, 1728 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..dd7c2df271d0
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -0,0 +1,131 @@
+/*
+ * 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;
+ struct kobject kobj;
+ 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..6330c0b6e7db
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -0,0 +1,629 @@
+/* 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 = 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 = (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) {
+ /* Get to the ICMPv6 header */
+ *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 it's a PAUSE frame discard it! */
+ 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;
+ ndmh = (struct nd_msg *)lyr3h;
+
+ /* Make sure that the NeighborSolicitation ICMPv6 packets
+ * are handled to avoid DAD issue.
+ */
+ if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+ /* Reach the target address */
+ 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)
+ /* Skip 2 L2 headers + 1 src L3 (IPv4) header */
+ arp_ptr += (2 * port->dev->addr_len) + 4;
+ else
+ /* Skip L2 header to get to src L3 (IPv4) */
+ arp_ptr += port->dev->addr_len;
+
+ memcpy(&dip, arp_ptr, 4); /* Get the dst IPv4 */
+ 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;
+
+ netif_dbg(ipvlan, pktdata, ipvlan->dev, "L3:Xmit on dev %s,PROT=%x\n",
+ dev->name, ntohs(skb->protocol));
+ 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:
+ /* Send it 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;
+
+ netif_dbg(ipvlan, pktdata, dev, "L2:Xmit on dev %s,PROT=%x\n",
+ dev->name, ntohs(skb->protocol));
+ if (ether_addr_equal(eth->h_dest, eth->h_source)) {
+ netif_dbg(ipvlan, pktdata, dev,
+ "Comm betn 2 virt devs PROT=%x\n",
+ ntohs(skb->protocol));
+ if ((lyr3h = ipvlan_get_L3_hdr(skb, &addr_type)) == NULL)
+ goto to_default;
+
+ addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
+ if (addr)
+ return ipvlan_rcv_frame(addr, skb, true);
+
+ /* No matching ipvlan dev! Must be on the Physical device */
+to_default:
+ 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;
+ /* Packet needs to be multicast-ed. */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_dbg(ipvlan, pktdata, dev,
+ "%s[%d] Mcast Xmit on [%s], PROT=[%x]\n",
+ __func__, __LINE__, dev->name, ntohs(skb->protocol));
+ ipvlan_multicast_frame(ipvlan->port, skb, ipvlan, true);
+ skb->ip_summed = ip_summed;
+ }
+
+ /* Send it out */
+ 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 */
+ BUG();
+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)) {
+ if ((lyr3h = ipvlan_get_L3_hdr(skb, &addr_type)) == NULL)
+ 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) {
+ netif_dbg(addr->master, pktdata, addr->master->dev,
+ "%s[%d]L3:Ucast Recv for [%s], PROT=[%x]\n",
+ __func__, __LINE__, addr->master->dev->name,
+ ntohs(skb->protocol));
+ 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;
+
+ /* First Handle broadcast/multicast frames */
+ if (is_multicast_ether_addr(eth->h_dest)) {
+ /* Pass to virtual devs only if they haven't seen the frame. */
+ if (ipvlan_external_frame(skb, port))
+ ipvlan_multicast_frame(port, skb, NULL, false);
+
+ } else if ((lyr3h = ipvlan_get_L3_hdr(skb, &addr_type)) != NULL) {
+ struct ipvl_addr *addr;
+
+ addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
+ if (addr) {
+ netif_dbg(addr->master, pktdata, addr->master->dev,
+ "%s[%d]L2:Ucast Recv:[%s], PROT=[%x]\n",
+ __func__, __LINE__, addr->master->dev->name,
+ ntohs(skb->protocol));
+ 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)
+ goto out;
+
+ 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 */
+ BUG();
+out:
+ return RX_HANDLER_PASS;
+}
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
new file mode 100644
index 000000000000..4157f180ea95
--- /dev/null
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -0,0 +1,815 @@
+/* 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, "%s[%d]: The master dev is either lo or non-ethernet\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ if ((port = kzalloc(sizeof(struct ipvl_port), GFP_KERNEL)) == NULL)
+ 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 broadcast hash-bit (for IPv4) */
+ __set_bit(hashbit, ipvlan->mac_filters);
+ } else if (!set && test_bit(hashbit, ipvlan->mac_filters)) {
+ /* Reset broadcast hash-bit */
+ __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 *stats)
+{
+ 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));
+
+ stats->rx_packets += rx_pkts;
+ stats->rx_bytes += rx_bytes;
+ stats->multicast += rx_mcast;
+ stats->tx_packets += tx_pkts;
+ stats->tx_bytes += tx_bytes;
+
+ /* u32 values are updated without syncp protection. */
+ rx_errs += pcptr->rx_errs;
+ tx_drps += pcptr->tx_drps;
+ }
+ stats->rx_errors = rx_errs;
+ stats->rx_dropped = rx_errs;
+ stats->tx_dropped = tx_drps;
+ }
+ return stats;
+}
+
+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 == NULL)
+ 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);
+ /* Get the mode if specified. */
+ 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;
+
+ /* Probably put a 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);
+
+ /* Mark this as a IPVLAN secondary device. */
+ 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,
+ "%s[%d]: Failed IPv6=%x:%x:%x:%x address for %s intf\n",
+ __func__, __LINE__, ip6_addr->s6_addr32[0],
+ ip6_addr->s6_addr32[1], ip6_addr->s6_addr32[2],
+ ip6_addr->s6_addr32[3], ipvlan->dev->name);
+ return -EINVAL;
+ }
+ if ((addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ netdev_dbg(ipvlan->dev,
+ "%s[%d]: Adding IPv6=%x:%x:%x:%x address for %s intf\n",
+ __func__, __LINE__, ip6_addr->s6_addr32[0],
+ ip6_addr->s6_addr32[1], ip6_addr->s6_addr32[2],
+ ip6_addr->s6_addr32[3], ipvlan->dev->name);
+ 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;
+
+ if ((addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true)) ==NULL)
+ return;
+
+ netdev_dbg(ipvlan->dev,
+ "%s[%d]: Deleting IPv6=%x:%x:%x:%x address for %s intf.\n",
+ __func__, __LINE__, ip6_addr->s6_addr32[0],
+ ip6_addr->s6_addr32[1], ip6_addr->s6_addr32[2],
+ ip6_addr->s6_addr32[3], ipvlan->dev->name);
+ /* Delete from the hash-table */
+ ipvlan_ht_addr_del(addr, true);
+ /* Delete from the logical's addr list */
+ 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,
+ "%s[%d]: Failed to add IPv4=%x on %s intf.\n",
+ __func__, __LINE__, ntohl(ip4_addr->s_addr),
+ ipvlan->dev->name);
+ return -EINVAL;
+ }
+ if ((addr = kzalloc(sizeof(struct ipvl_addr), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ netdev_dbg(ipvlan->dev,
+ "%s[%d]: Adding IPv4=%x address for %s intf.\n",
+ __func__, __LINE__, ip4_addr->s_addr, ipvlan->dev->name);
+ 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;
+
+ if ((addr= ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false)) ==NULL)
+ return;
+
+ netdev_dbg(ipvlan->dev,
+ "%s[%d]: Deleting IPv4=%x address for %s intf.\n",
+ __func__, __LINE__, ip4_addr->s_addr, ipvlan->dev->name);
+ /* Delete from the hash-table */
+ ipvlan_ht_addr_del(addr, true);
+ /* Delete from the logical's addr list */
+ 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 2/2] sh_eth: Fix asynchronous external abort
From: Simon Horman @ 2014-11-24 1:18 UTC (permalink / raw)
To: Yoshihiro Kaneko; +Cc: netdev, David S. Miller, Magnus Damm, linux-sh
In-Reply-To: <1415862135-27972-3-git-send-email-ykaneko0929@gmail.com>
Hi Kaneko-san, Hi All,
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
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.
> ----
> [ 792.240535] Unhandled fault: asynchronous external abort (0x1211) at 0x00000000
> [ 792.262485] Internal error: : 1211 [#1] PREEMPT SMP ARM
> [ 792.278165] Modules linked in:
> [ 792.287340] CPU: 1 PID: 1495 Comm: ethtool Not tainted 3.10.31-ltsi-00046-gefa0b46-dirty #1089
> [ 792.313195] task: d68e30c0 ti: d6878000 task.ti: d6878000
> [ 792.329404] PC is at sh_eth_reset+0x2cc/0x3a8
> [ 792.342476] LR is at sh_eth_dmac_init+0x18/0x374
> [ 792.356327] pc : [<c029907c>] lr : [<c029ed20>] psr: 20070013
> [ 792.356327] sp : d6879d78 ip : d6879d98 fp : d6879d94
> [ 792.390792] r10: d6385c80 r9 : d6878000 r8 : 00000000
> [ 792.406470] r7 : 00000000 r6 : 00000000 r5 : 00000001 r4 : d6385800
> [ 792.426061] r3 : e78dc200 r2 : e78dc000 r1 : 00000000 r0 : d6385800
> [ 792.445653] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
> [ 792.467072] Control: 30c53c7d Table: 55c0a140 DAC: 55555555
> [ 792.484315] Process ethtool (pid: 1495, stack limit = 0xd6878238)
> [ 792.502601] Stack: (0xd6879d78 to 0xd687a000)
> [ 792.515669] 9d60: c049ca32 d6385800
> [ 792.540221] 9d80: 00000000 00000000 d6879dbc d6879d98 c029ed20 c0298dbc c049ca32 d6385800
> [ 792.564771] 9da0: 00000000 c06502c0 00000000 00000000 d6879dec d6879dc0 c029f7c8 c029ed14
> [ 792.589321] 9dc0: c029f610 be976b6c 00000011 c06502c0 00000000 00000000 d6878000 d6385800
> [ 792.613871] 9de0: d6879e6c d6879df0 c03b70f0 c029f61c 00004000 00000000 d6879e1c 00000011
> [ 792.638420] 9e00: 00000000 00000000 00000000 d6160000 00000011 00000400 00000000 00000000
> [ 792.662969] 9e20: 00000400 00000400 00000000 00000000 00000040 00000000 d6879e5c d6879e48
> [ 792.687519] 9e40: c0452f20 00008946 be976c20 c06502c0 00000000 00000000 d6878000 be976c20
> [ 792.712069] 9e60: d6879ec4 d6879e70 c03c4870 c03b64f0 000000d0 d69d1a40 30687465 00000000
> [ 792.736618] 9e80: 00000000 00000000 be976b6c 00000000 00000000 00000000 c03f85e0 00008946
> [ 792.761168] 9ea0: fffffdfd be976c20 00008946 d65686a0 d6878000 be976c20 d6879ee4 d6879ec8
> [ 792.785717] 9ec0: c039feb0 c03c435c c039fc48 be976c20 d6ae38c0 00000003 d6879ef4 d6879ee8
> [ 792.810267] 9ee0: c00c8540 c039fc54 d6879f74 d6879ef8 c00c9114 c00c851c d6879fac d6879f08
> [ 792.834817] 9f00: c0009288 c001b168 d6879f40 00000003 d6879f3c d6879f20 c00bafe0 c00bae6c
> [ 792.859366] 9f20: d6879f44 d6879f30 d6879f44 d6879f38 c0454c04 c0049738 d6879f64 d6879f48
> [ 792.883916] 9f40: c00d2978 c0454be4 00000003 be976c20 d6ae38c0 00000000 00008946 00000003
> [ 792.908466] 9f60: d6878000 00000000 d6879fa4 d6879f78 c00c91ac c00c8b84 d6879fb0 00000000
> [ 792.933015] 9f80: d6879fac be976c18 be976b88 be976b60 00000036 c000f068 00000000 d6879fa8
> [ 792.957565] 9fa0: c000eec0 c00c9178 be976c18 be976b88 00000003 00008946 be976c20 be976c18
> [ 792.982114] 9fc0: be976c18 be976b88 be976b60 00000036 be976b5c be976b58 be976b80 0001f754
> [ 793.006664] 9fe0: 000433f0 be976b4c 0000d8e8 b6e035ac 200d0010 00000003 c90515a9 0f9c2043
> [ 793.031212] Backtrace:
> [ 793.038564] [<c0298db0>] (sh_eth_reset+0x0/0x3a8) from [<c029ed20>] (sh_eth_dmac_init+0x18/0x374)
> [ 793.065199] r6:00000000 r5:00000000 r4:d6385800 r3:c049ca32
> [ 793.082257] [<c029ed08>] (sh_eth_dmac_init+0x0/0x374) from [<c029f7c8>] (sh_eth_set_ringparam+0x1b8/0x2cc)
> [ 793.111241] r8:00000000 r7:00000000 r6:c06502c0 r5:00000000 r4:d6385800
> r3:c049ca32
> [ 793.134860] [<c029f610>] (sh_eth_set_ringparam+0x0/0x2cc) from [<c03b70f0>] (dev_ethtool+0xc0c/0x1e4c)
> [ 793.162807] [<c03b64e4>] (dev_ethtool+0x0/0x1e4c) from [<c03c4870>] (dev_ioctl+0x520/0x688)
> [ 793.187881] [<c03c4350>] (dev_ioctl+0x0/0x688) from [<c039feb0>] (sock_ioctl+0x268/0x2a0)
> [ 793.212435] [<c039fc48>] (sock_ioctl+0x0/0x2a0) from [<c00c8540>] (vfs_ioctl+0x30/0x44)
> [ 793.236461] r6:00000003 r5:d6ae38c0 r4:be976c20 r3:c039fc48
> [ 793.253516] [<c00c8510>] (vfs_ioctl+0x0/0x44) from [<c00c9114>] (do_vfs_ioctl+0x59c/0x5f4)
> [ 793.278328] [<c00c8b78>] (do_vfs_ioctl+0x0/0x5f4) from [<c00c91ac>] (SyS_ioctl+0x40/0x68)
> [ 793.302882] [<c00c916c>] (SyS_ioctl+0x0/0x68) from [<c000eec0>] (ret_fast_syscall+0x0/0x30)
> [ 793.327952] r8:c000f068 r7:00000036 r6:be976b60 r5:be976b88 r4:be976c18
> [ 793.348155] Code: e0823003 e5935000 f57ff04f e3855001 (f57ff04f)
> [ 793.366445] ---[ end trace 6885a6a6c1fc41e3 ]---
> ----
>
> Signed-off-by: Mitsuhiro Kimura <mitsuhiro.kimura.kc@renesas.com>
> Signed-off-by: Yoshihiro Kaneko <ykaneko0929@gmail.com>
> ---
> drivers/net/ethernet/renesas/sh_eth.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
> index 862a691..dadbd00 100644
> --- a/drivers/net/ethernet/renesas/sh_eth.c
> +++ b/drivers/net/ethernet/renesas/sh_eth.c
> @@ -1839,6 +1839,9 @@ static int sh_eth_set_settings(struct net_device *ndev,
> unsigned long flags;
> int ret;
>
> + if (!mdp->is_opened)
> + return -EAGAIN;
> +
> spin_lock_irqsave(&mdp->lock, flags);
>
> /* disable tx and rx */
> @@ -1975,6 +1978,9 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
> mdp->num_rx_ring = ring->rx_pending;
> mdp->num_tx_ring = ring->tx_pending;
>
> + if (!mdp->is_opened)
> + return 0;
> +
> ret = sh_eth_ring_init(ndev);
> if (ret < 0) {
> netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__);
> --
> 1.9.1
>
^ permalink raw reply
* Re: [PATCH 1/2] virito: introduce methods of fixing device features
From: Rusty Russell @ 2014-11-24 1:08 UTC (permalink / raw)
To: Jason Wang, mst, virtualization, linux-kernel; +Cc: netdev
In-Reply-To: <1415857974-23326-1-git-send-email-jasowang@redhat.com>
Jason Wang <jasowang@redhat.com> writes:
> Buggy host may advertised buggy host features (a usual case is that host
> advertise a feature whose dependencies were missed). In this case, driver
> should detect and disable the buggy features by itself.
Sorry, I've been focussing elsewhere.
I would really prefer that drivers offer a "feature_depends" table,
which can indicate that feature A depends on feature B, and have the
core iterate, complain and fixup as necessary.
Is that expressive enough, or do we need more?
Thanks,
Rusty.
^ permalink raw reply
* Re: [PATCH 08/17] {macvtap,tun}_get_user(): switch to iov_iter
From: Ben Hutchings @ 2014-11-24 1:06 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <1416788862.7215.65.camel@decadent.org.uk>
[-- Attachment #1: Type: text/plain, Size: 641 bytes --]
On Mon, 2014-11-24 at 00:27 +0000, Ben Hutchings wrote:
> On Sat, 2014-11-22 at 04:33 +0000, Al Viro wrote:
[...]
> Does skb_copy_datagram_from_iter() really need a len parameter? Here it
> is equal to iov_iter_count(from).
[...]
> Again len is equal to iov_iter_count(from), so I think that parameter is
> redundant.
Having read further patches, I see that unix_stream_sendmsg() is the one
exception where the length parameter is different. But maybe the common
case (len = iter_iov_count(iov)) deserves a wrapper function?
Ben.
--
Ben Hutchings
Absolutum obsoletum. (If it works, it's out of date.) - Stafford Beer
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ 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 0:32 UTC (permalink / raw)
To: Jeff Layton
Cc: Pieter Smith, 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: <20141123192810.682a223e-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
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
^ permalink raw reply
* Re: [PATCH 07/17] new helpers: skb_copy_datagram_from_iter() and zerocopy_sg_from_iter()
From: Ben Hutchings @ 2014-11-24 0:29 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <1416787365.7215.63.camel@decadent.org.uk>
[-- Attachment #1: Type: text/plain, Size: 514 bytes --]
On Mon, 2014-11-24 at 00:02 +0000, 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.
[...]
Never mind, I can see that patches 9 and 10 recycle the _iovec
functions' kernel-doc comments.
Ben.
--
Ben Hutchings
Absolutum obsoletum. (If it works, it's out of date.) - Stafford Beer
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ permalink raw reply
* Re: [PATCH 0/6] kernel tinification: optionally compile out splice family of syscalls (splice, vmsplice, tee and sendfile)
From: Jeff Layton @ 2014-11-24 0:28 UTC (permalink / raw)
To: Josh Triplett
Cc: Pieter Smith, David Miller, alexander.h.duyck, viro, ast, akpm,
beber, catalina.mocanu, dborkman, edumazet, ebiederm, fabf,
fuse-devel, geert, hughd, iulia.manda21, JBeulich, bfields,
linux-api, linux-fsdevel, linux-kernel, mcgrof, mattst88, mgorman,
mst, miklos, netdev, oleg, Paul.Durrant, paulmck, pefoley2, tgraf,
therbert, willemb, xiaoguangrong, zhenglong.cai
In-Reply-To: <20141123233637.GC12456@thin>
On Sun, 23 Nov 2014 15:36:37 -0800
Josh Triplett <josh@joshtriplett.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.
> That said, given that it seems exceedingly unlikely that anyone would
> use the in-kernel nfsd on a system trying to minimize kernel size, it
> still seems cleaner to just "select SPLICE_SYSCALL" from NFSD in
> Kconfig. That avoids making any changes at all to the nfsd source in
> this patch series.
>
--
Jeff Layton <jlayton@poochiereds.net>
^ permalink raw reply
* Re: [PATCH 08/17] {macvtap,tun}_get_user(): switch to iov_iter
From: Ben Hutchings @ 2014-11-24 0:27 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <20141122043352.GH30478@ZenIV.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 6827 bytes --]
On Sat, 2014-11-22 at 04:33 +0000, Al Viro wrote:
> allows to switch macvtap and tun from ->aio_write() to ->write_iter()
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> drivers/net/macvtap.c | 43 ++++++++++++++++++++-----------------------
> drivers/net/tun.c | 43 +++++++++++++++++++++++--------------------
> 2 files changed, 43 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> index cdd820f..2bf08c6 100644
> --- a/drivers/net/macvtap.c
> +++ b/drivers/net/macvtap.c
> @@ -640,12 +640,12 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
>
> /* Get packet from user space buffer */
> static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
> - const struct iovec *iv, unsigned long total_len,
> - size_t count, int noblock)
> + struct iov_iter *from, int noblock)
> {
> int good_linear = SKB_MAX_HEAD(NET_IP_ALIGN);
> struct sk_buff *skb;
> struct macvlan_dev *vlan;
> + unsigned long total_len = iov_iter_count(from);
> unsigned long len = total_len;
> int err;
> struct virtio_net_hdr vnet_hdr = { 0 };
> @@ -653,6 +653,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
> int copylen = 0;
> bool zerocopy = false;
> size_t linear;
> + ssize_t n;
>
> if (q->flags & IFF_VNET_HDR) {
> vnet_hdr_len = q->vnet_hdr_sz;
> @@ -662,10 +663,11 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
> goto err;
> len -= vnet_hdr_len;
>
> - err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0,
> - sizeof(vnet_hdr));
> - if (err < 0)
> + err = -EFAULT;
> + n = copy_from_iter(&vnet_hdr, sizeof(vnet_hdr), from);
> + if (n != sizeof(vnet_hdr))
> goto err;
> + iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
> if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
> vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
> vnet_hdr.hdr_len)
> @@ -680,17 +682,15 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
> if (unlikely(len < ETH_HLEN))
> goto err;
>
> - err = -EMSGSIZE;
> - if (unlikely(count > UIO_MAXIOV))
> - goto err;
> -
> if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
> + struct iov_iter i;
Blank line needed after a declaration.
> 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.
> zerocopy = true;
> }
>
> @@ -708,10 +708,9 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
> goto err;
>
> if (zerocopy)
> - err = zerocopy_sg_from_iovec(skb, iv, vnet_hdr_len, count);
> + err = zerocopy_sg_from_iter(skb, from);
> else {
> - err = skb_copy_datagram_from_iovec(skb, 0, iv, vnet_hdr_len,
> - len);
> + err = skb_copy_datagram_from_iter(skb, 0, from, len);
Does skb_copy_datagram_from_iter() really need a len parameter? Here it
is equal to iov_iter_count(from).
[...]
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -1012,28 +1012,29 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,
>
> /* Get packet from user space buffer */
> static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> - void *msg_control, const struct iovec *iv,
> - size_t total_len, size_t count, int noblock)
> + void *msg_control, struct iov_iter *from,
> + int noblock)
> {
> struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
> struct sk_buff *skb;
> + size_t total_len = iov_iter_count(from);
> size_t len = total_len, align = NET_SKB_PAD, linear;
> struct virtio_net_hdr gso = { 0 };
> int good_linear;
> - int offset = 0;
> int copylen;
> bool zerocopy = false;
> int err;
> u32 rxhash;
> + ssize_t n;
>
> if (!(tun->flags & TUN_NO_PI)) {
> if (len < sizeof(pi))
> return -EINVAL;
> len -= sizeof(pi);
>
> - if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi)))
> + n = copy_from_iter(&pi, sizeof(pi), from);
> + if (n != sizeof(pi))
> return -EFAULT;
> - offset += sizeof(pi);
> }
>
> if (tun->flags & TUN_VNET_HDR) {
> @@ -1041,7 +1042,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> return -EINVAL;
> len -= tun->vnet_hdr_sz;
>
> - if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
> + n = copy_from_iter(&gso, sizeof(gso), from);
> + if (n != sizeof(gso))
> return -EFAULT;
>
> if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
> @@ -1050,7 +1052,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
>
> if (gso.hdr_len > len)
> return -EINVAL;
> - offset += tun->vnet_hdr_sz;
> + iov_iter_advance(from, tun->vnet_hdr_sz);
tun->vnet_hdr_sz - sizeof(gso)
> }
>
> if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
> @@ -1063,6 +1065,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> good_linear = SKB_MAX_HEAD(align);
>
> if (msg_control) {
> + struct iov_iter i = *from;
Blank line needed after a declaration.
> /* There are 256 bytes to be copied in skb, so there is
> * enough room for skb expand head in case it is used.
> * The rest of the buffer is mapped from userspace.
> @@ -1071,7 +1074,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> if (copylen > good_linear)
> copylen = good_linear;
> linear = copylen;
> - if (iov_pages(iv, offset + copylen, count) <= MAX_SKB_FRAGS)
> + iov_iter_advance(&i, copylen);
> + if (iov_iter_npages(&i, INT_MAX) <= MAX_SKB_FRAGS)
Again, the maxpages argument should be MAX_SKB_FRAGS + 1.
> zerocopy = true;
> }
>
> @@ -1091,9 +1095,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> }
>
> if (zerocopy)
> - err = zerocopy_sg_from_iovec(skb, iv, offset, count);
> + err = zerocopy_sg_from_iter(skb, from);
> else {
> - err = skb_copy_datagram_from_iovec(skb, 0, iv, offset, len);
> + err = skb_copy_datagram_from_iter(skb, 0, from, len);
[...]
Again len is equal to iov_iter_count(from), so I think that parameter is
redundant.
Ben.
--
Ben Hutchings
Absolutum obsoletum. (If it works, it's out of date.) - Stafford Beer
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ permalink raw reply
* Re: [PATCH 07/17] new helpers: skb_copy_datagram_from_iter() and zerocopy_sg_from_iter()
From: Ben Hutchings @ 2014-11-24 0:02 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <20141122043320.GG30478@ZenIV.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 4179 bytes --]
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?
> + copied -= size;
> + i++, n++;
> + }
> + if (i > MAX_SKB_FRAGS)
> + return -EMSGSIZE;
Same here.
Ben.
> + }
> + return 0;
> +}
> +EXPORT_SYMBOL(zerocopy_sg_from_iter);
> +
> static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
> u8 __user *to, int len,
> __wsum *csump)
--
Ben Hutchings
Never put off till tomorrow what you can avoid all together.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ 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-23 23:36 UTC (permalink / raw)
To: Pieter Smith
Cc: 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, jlayton-vpEMnDpepFuMZCB2o+C8xQ,
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: <20141123203040.GB26749@smipidev>
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.
That said, given that it seems exceedingly unlikely that anyone would
use the in-kernel nfsd on a system trying to minimize kernel size, it
still seems cleaner to just "select SPLICE_SYSCALL" from NFSD in
Kconfig. That avoids making any changes at all to the nfsd source in
this patch series.
- Josh Triplett
^ permalink raw reply
* Re: [PATCH 06/17] switch macvtap to ->read_iter()
From: Ben Hutchings @ 2014-11-23 23:29 UTC (permalink / raw)
To: Al Viro
Cc: David Miller, torvalds, netdev, linux-kernel, target-devel, nab,
hch
In-Reply-To: <20141122043230.GF30478@ZenIV.linux.org.uk>
[-- Attachment #1: Type: text/plain, Size: 1533 bytes --]
On Sat, 2014-11-22 at 04:32 +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> drivers/net/macvtap.c | 39 ++++++++++++++++-----------------------
> 1 file changed, 16 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> index cea99d4..cdd820f 100644
> --- a/drivers/net/macvtap.c
> +++ b/drivers/net/macvtap.c
> @@ -829,16 +829,17 @@ done:
> }
>
> static ssize_t macvtap_do_read(struct macvtap_queue *q,
> - const struct iovec *iv, unsigned long segs,
> - unsigned long len,
> + struct iov_iter *to,
> int noblock)
> {
> DEFINE_WAIT(wait);
> struct sk_buff *skb;
> ssize_t ret = 0;
> - struct iov_iter iter;
>
> - while (len) {
> + if (!iov_iter_count(to))
> + return 0;
> +
> + while (1) {
> if (!noblock)
> prepare_to_wait(sk_sleep(&q->sk), &wait,
> TASK_INTERRUPTIBLE);
> @@ -856,37 +857,27 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q,
> }
> /* Nothing to read, let's sleep */
> schedule();
> - continue;
> }
> - iov_iter_init(&iter, READ, iv, segs, len);
> - ret = macvtap_put_user(q, skb, &iter);
> + }
> + if (skb) {
> + ret = macvtap_put_user(q, skb, to);
> kfree_skb(skb);
> - break;
[...]
You need to leave this break at the bottom of the loop body, or change
it to:
do {
...
} while (!skb);
Ben.
--
Ben Hutchings
Never put off till tomorrow what you can avoid all together.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 811 bytes --]
^ permalink raw reply
* Re: [fuse-devel] [PATCH 4/6] fs/fuse: support compiling out splice
From: Josh Triplett @ 2014-11-23 23:23 UTC (permalink / raw)
To: Richard Weinberger
Cc: Pieter Smith, 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: <CAFLxGvxq3Mr9n8xMO_fPZDhrGmBh=WKyU0+RF13JBdjssX6qfw@mail.gmail.com>
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
^ permalink raw reply
* Re: [fuse-devel] [PATCH 4/6] fs/fuse: support compiling out splice
From: Richard Weinberger @ 2014-11-23 22:29 UTC (permalink / raw)
To: Pieter Smith
Cc: 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, Josh Triplett
In-Reply-To: <1416752468-1626-5-git-send-email-pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>
On Sun, Nov 23, 2014 at 3:20 PM, Pieter Smith <pieter-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org> 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-qeJ+1H9vRZbz+pZb47iToQ@public.gmane.org>
> ---
> 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. :-)
--
Thanks,
//richard
^ permalink raw reply
* Re: [PATCH net-next v2] ipv6: coding style improvements (remove assignment in if statements)
From: Joe Perches @ 2014-11-23 21:50 UTC (permalink / raw)
To: Ian Morris; +Cc: netdev
In-Reply-To: <1416778123-5803-1-git-send-email-ipm@chirality.org.uk>
On Sun, 2014-11-23 at 21:28 +0000, Ian Morris wrote:
> This change has no functional impact and simply addresses some coding
> style issues detected by checkpatch. Specifically this change
> adjusts "if" statements which also include the assignment of a
> variable.
Unrelated trivia:
> net/ipv6/addrconf.c | 12 ++++++++----
[]
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
[]
> @@ -2690,7 +2691,8 @@ static void init_loopback(struct net_device *dev)
>
> ASSERT_RTNL();
>
> - if ((idev = ipv6_find_idev(dev)) == NULL) {
> + idev = ipv6_find_idev(dev);
> + if (idev == NULL) {
> pr_debug("%s: add_dev failed\n", __func__);
> return;
> }
> @@ -2813,7 +2815,8 @@ static void addrconf_sit_config(struct net_device *dev)
> * our v4 addrs in the tunnel
> */
>
> - if ((idev = ipv6_find_idev(dev)) == NULL) {
> + idev = ipv6_find_idev(dev);
> + if (idev == NULL) {
> pr_debug("%s: add_dev failed\n", __func__);
> return;
> }
> @@ -2837,7 +2840,8 @@ static void addrconf_gre_config(struct net_device *dev)
>
> ASSERT_RTNL();
>
> - if ((idev = ipv6_find_idev(dev)) == NULL) {
> + idev = ipv6_find_idev(dev);
> + if (idev == NULL) {
> pr_debug("%s: add_dev failed\n", __func__);
> return;
> }
It looks like these should not be "add_dev failed"
but "ipv6_find_idev failed"
^ permalink raw reply
* Personal
From: Patrick McSweeney @ 2014-11-23 21:31 UTC (permalink / raw)
--
I have a proposal with mutual benefit for you, contact me for more
information.
Regards
Patrick
^ permalink raw reply
* [PATCH net-next v2] ipv6: coding style improvements (remove assignment in if statements)
From: Ian Morris @ 2014-11-23 21:28 UTC (permalink / raw)
To: netdev; +Cc: Ian Morris
This change has no functional impact and simply addresses some coding
style issues detected by checkpatch. Specifically this change
adjusts "if" statements which also include the assignment of a
variable.
No changes to the resultant object files result as determined by objdiff.
Signed-off-by: Ian Morris <ipm@chirality.org.uk>
---
net/ipv6/addrconf.c | 12 ++++++++----
net/ipv6/ah6.c | 7 ++++---
net/ipv6/esp6.c | 3 ++-
net/ipv6/icmp.c | 3 ++-
net/ipv6/ip6_flowlabel.c | 6 +++++-
net/ipv6/ip6_input.c | 3 ++-
net/ipv6/ip6_output.c | 12 ++++++++----
net/ipv6/ip6_tunnel.c | 15 ++++++++-------
net/ipv6/ip6_vti.c | 4 ++--
net/ipv6/ndisc.c | 7 ++++---
net/ipv6/reassembly.c | 3 ++-
net/ipv6/sit.c | 7 ++++---
net/ipv6/udp.c | 6 ++++--
13 files changed, 55 insertions(+), 33 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 251fcb4..9eac3a7 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2543,7 +2543,8 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
if (!dev)
return -ENODEV;
- if ((idev = __in6_dev_get(dev)) == NULL)
+ idev = __in6_dev_get(dev);
+ if (idev == NULL)
return -ENXIO;
read_lock_bh(&idev->lock);
@@ -2690,7 +2691,8 @@ static void init_loopback(struct net_device *dev)
ASSERT_RTNL();
- if ((idev = ipv6_find_idev(dev)) == NULL) {
+ idev = ipv6_find_idev(dev);
+ if (idev == NULL) {
pr_debug("%s: add_dev failed\n", __func__);
return;
}
@@ -2813,7 +2815,8 @@ static void addrconf_sit_config(struct net_device *dev)
* our v4 addrs in the tunnel
*/
- if ((idev = ipv6_find_idev(dev)) == NULL) {
+ idev = ipv6_find_idev(dev);
+ if (idev == NULL) {
pr_debug("%s: add_dev failed\n", __func__);
return;
}
@@ -2837,7 +2840,8 @@ static void addrconf_gre_config(struct net_device *dev)
ASSERT_RTNL();
- if ((idev = ipv6_find_idev(dev)) == NULL) {
+ idev = ipv6_find_idev(dev);
+ if (idev == NULL) {
pr_debug("%s: add_dev failed\n", __func__);
return;
}
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 8ab1989..a6727ad 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -353,7 +353,8 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
ahp = x->data;
ahash = ahp->ahash;
- if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ err = skb_cow_data(skb, 0, &trailer);
+ if (err < 0)
goto out;
nfrags = err;
@@ -559,8 +560,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
if (!pskb_may_pull(skb, ah_hlen))
goto out;
-
- if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+ err = skb_cow_data(skb, 0, &trailer);
+ if (err < 0)
goto out;
nfrags = err;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index d2c2d74..e48f2c7 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -345,7 +345,8 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
goto out;
}
- if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
+ nfrags = skb_cow_data(skb, 0, &trailer);
+ if (nfrags < 0) {
ret = -EINVAL;
goto out;
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 39b3ff9..d674152 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -243,7 +243,8 @@ int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
struct icmp6hdr *icmp6h;
int err = 0;
- if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
+ skb = skb_peek(&sk->sk_write_queue);
+ if (skb == NULL)
goto out;
icmp6h = icmp6_hdr(skb);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 7221021..2f780cb 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -654,7 +654,11 @@ release:
goto done;
err = -ENOMEM;
- if (sfl1 == NULL || (err = mem_check(sk)) != 0)
+ if (sfl1 == NULL)
+ goto done;
+
+ err = mem_check(sk);
+ if (err != 0)
goto done;
fl1 = fl_intern(net, fl, freq.flr_label);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index a3084ab..aacdcb4 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -220,7 +220,8 @@ resubmit:
nexthdr = skb_network_header(skb)[nhoff];
raw = raw6_local_deliver(skb, nexthdr);
- if ((ipprot = rcu_dereference(inet6_protos[nexthdr])) != NULL) {
+ ipprot = rcu_dereference(inet6_protos[nexthdr]);
+ if (ipprot != NULL) {
int ret;
if (ipprot->flags & INET6_PROTO_FINAL) {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 916d2a1..ce69a12 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -898,7 +898,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
if (*dst == NULL)
*dst = ip6_route_output(net, sk, fl6);
- if ((err = (*dst)->error))
+ err = (*dst)->error;
+ if (err)
goto out_err_release;
if (ipv6_addr_any(&fl6->saddr)) {
@@ -946,7 +947,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
memcpy(&fl_gw6, fl6, sizeof(struct flowi6));
memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr));
*dst = ip6_route_output(net, sk, &fl_gw6);
- if ((err = (*dst)->error))
+ err = (*dst)->error;
+ if (err)
goto out_err_release;
}
}
@@ -1054,7 +1056,8 @@ static inline int ip6_ufo_append_data(struct sock *sk,
* device, so create one single skb packet containing complete
* udp datagram
*/
- if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) {
+ skb = skb_peek_tail(&sk->sk_write_queue);
+ if (skb == NULL) {
skb = sock_alloc_send_skb(sk,
hh_len + fragheaderlen + transhdrlen + 20,
(flags & MSG_DONTWAIT), &err);
@@ -1534,7 +1537,8 @@ int ip6_push_pending_frames(struct sock *sk)
unsigned char proto = fl6->flowi6_proto;
int err = 0;
- if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL)
+ skb = __skb_dequeue(&sk->sk_write_queue);
+ if (skb == NULL)
goto out;
tail_skb = &(skb_shinfo(skb)->frag_list);
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index e2b6cfb..92b3da5 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -501,8 +501,8 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
processing of the error. */
rcu_read_lock();
- if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr,
- &ipv6h->saddr)) == NULL)
+ t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr);
+ if (t == NULL)
goto out;
tproto = ACCESS_ONCE(t->parms.proto);
@@ -550,7 +550,8 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
mtu = IPV6_MIN_MTU;
t->dev->mtu = mtu;
- if ((len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
+ len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len);
+ if (len > mtu) {
rel_type = ICMPV6_PKT_TOOBIG;
rel_code = 0;
rel_info = mtu;
@@ -811,9 +812,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
int err;
rcu_read_lock();
-
- if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
- &ipv6h->daddr)) != NULL) {
+ t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
+ if (t != NULL) {
struct pcpu_sw_netstats *tstats;
tproto = ACCESS_ONCE(t->parms.proto);
@@ -1069,7 +1069,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb;
- if (!(new_skb = skb_realloc_headroom(skb, max_headroom)))
+ new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb)
goto tx_err_dst_release;
if (skb->sk)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index ec84d03..8308216 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -287,8 +287,8 @@ static int vti6_rcv(struct sk_buff *skb)
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
rcu_read_lock();
- if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
- &ipv6h->daddr)) != NULL) {
+ t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
+ if (t != NULL) {
if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
rcu_read_unlock();
goto discard;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2c9f6bf..6828667 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -162,7 +162,8 @@ static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
memcpy(opt+2, data, data_len);
data_len += 2;
opt += data_len;
- if ((space -= data_len) > 0)
+ space -= data_len;
+ if (space > 0)
memset(opt, 0, space);
}
@@ -656,8 +657,8 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
saddr = &ipv6_hdr(skb)->saddr;
-
- if ((probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES)) < 0) {
+ probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
+ if (probes < 0) {
if (!(neigh->nud_state & NUD_VALID)) {
ND_PRINTK(1, dbg,
"%s: trying to ucast probe in NUD_INVALID: %pI6\n",
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 51ab096..d7d70e6 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -429,7 +429,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
struct sk_buff *clone;
int i, plen = 0;
- if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
+ clone = alloc_skb(0, GFP_ATOMIC);
+ if (clone == NULL)
goto out_oom;
clone->next = head->next;
head->next = clone;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 660496d..213546b 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1241,7 +1241,8 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
goto done;
err = -ENOENT;
- if ((t = ipip6_tunnel_locate(net, &p, 0)) == NULL)
+ t = ipip6_tunnel_locate(net, &p, 0);
+ if (t == NULL)
goto done;
err = -EPERM;
if (t == netdev_priv(sitn->fb_tunnel_dev))
@@ -1836,8 +1837,8 @@ static int __net_init sit_init_net(struct net *net)
goto err_dev_free;
ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
-
- if ((err = register_netdev(sitn->fb_tunnel_dev)))
+ err = register_netdev(sitn->fb_tunnel_dev);
+ if (err)
goto err_reg_dev;
t = netdev_priv(sitn->fb_tunnel_dev);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 0ba3de4..dbc0b04 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -357,7 +357,8 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
struct sock *sk;
const struct ipv6hdr *iph = ipv6_hdr(skb);
- if (unlikely(sk = skb_steal_sock(skb)))
+ sk = skb_steal_sock(skb);
+ if (unlikely(sk))
return sk;
return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport,
&iph->daddr, dport, inet6_iif(skb),
@@ -1026,7 +1027,8 @@ static int udp_v6_push_pending_frames(struct sock *sk)
fl6 = &inet->cork.fl.u.ip6;
/* Grab the skbuff where UDP header space exists. */
- if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
+ skb = skb_peek(&sk->sk_write_queue);
+ if (skb == NULL)
goto out;
/*
--
1.9.1
^ permalink raw reply related
* Re: [PATCH net-next] mlx4: fix mlx4_en_set_rxfh()
From: Joe Perches @ 2014-11-23 20:56 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Amir Vadai, Ben Hutchings, David S. Miller, netdev
In-Reply-To: <1416762320.17888.21.camel@edumazet-glaptop2.roam.corp.google.com>
On Sun, 2014-11-23 at 09:05 -0800, Eric Dumazet wrote:
> On Sun, 2014-11-23 at 18:53 +0200, Amir Vadai wrote:
> > > */
> > > for (i = 0; i < priv->rx_ring_num; i++) {
> > > + if (!ring_index)
> > > + continue;
> >
> > Why didn't you put the whole loop under the 'if'?
>
> To avoid adding one indentation on the block, and ease this code review.
>
> This is hardly fast path, and compiler does the optim for us anyway.
It might have been more sensible
to use break instead of continue
^ 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-23 20:30 UTC (permalink / raw)
To: Josh Triplett
Cc: David Miller, alexander.h.duyck, viro, ast, akpm, beber,
catalina.mocanu, dborkman, edumazet, ebiederm, fabf, fuse-devel,
geert, hughd, iulia.manda21, JBeulich, bfields, jlayton,
linux-api, linux-fsdevel, linux-kernel, mcgrof, mattst88, mgorman,
mst, miklos, netdev, oleg, Paul.Durrant, paulmck, pefoley2, tgraf,
therbert, willemb, xiaoguangrong, zhenglong.cai
In-Reply-To: <20141123194326.GB8517@thin>
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.
> Given the requirements of running a file server in the kernel, I'd
> expect CONFIG_NFSD to end up with several more selects of optional
> functionality in the future. It seems rather likely that the average
> embedded system will be compiling out NFS. :)
>
> Also, this patch series compiles out splice and sendfile, including
> several *users* of sendpage; it doesn't compile out the sendpage
> support/infrastructure itself.
>
> - Josh Triplett
^ permalink raw reply
* Re: [PATCH net-net 0/4] Increase the limit of tuntap queues
From: Michael S. Tsirkin @ 2014-11-23 20:30 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.134323.1154795102254868842.davem@davemloft.net>
On Sun, Nov 23, 2014 at 01:43:23PM -0500, David Miller wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Sun, 23 Nov 2014 12:46:23 +0200
>
> > 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?
> >
> > David, could you comment on this please?
>
> I don't want arbitrary limits imposed.
>
> Where does this "application" run? If it's in the host, then who
> cares? If they suck up all of their available memory with queue
> resources, it's their problem.
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.
--
MST
^ permalink raw reply
* [PATCH net-next] enic: use netdev_rss_key_fill() helper
From: Eric Dumazet @ 2014-11-23 20:27 UTC (permalink / raw)
To: David Miller
Cc: Christian Benvenuti, Govindarajulu Varadarajan, netdev,
Sujith Sankar
From: Eric Dumazet <edumazet@google.com>
Use of well known RSS key might increase attack surface.
Switch to a random one, using generic helper so that all
ports share a common key.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Christian Benvenuti <benve@cisco.com>
Cc: Govindarajulu Varadarajan <_govind@gmx.com>
Cc: Sujith Sankar <ssujith@cisco.com>
---
drivers/net/ethernet/cisco/enic/enic_main.c | 24 +++++++++---------
| 9 +++++-
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 46647407d585b54dba0baa5ef357401f17b7c167..86ee350e57f0e03bd79908ade0782d9af99646b4 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -1890,23 +1890,23 @@ static int enic_dev_hang_reset(struct enic *enic)
static int enic_set_rsskey(struct enic *enic)
{
+ union vnic_rss_key *rss_key_buf_va;
dma_addr_t rss_key_buf_pa;
- union vnic_rss_key *rss_key_buf_va = NULL;
- union vnic_rss_key rss_key = {
- .key[0].b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101},
- .key[1].b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101},
- .key[2].b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115},
- .key[3].b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108},
- };
- int err;
+ u8 rss_key[ENIC_RSS_LEN];
+ int i, kidx, bidx, err;
- rss_key_buf_va = pci_alloc_consistent(enic->pdev,
- sizeof(union vnic_rss_key), &rss_key_buf_pa);
+ rss_key_buf_va = pci_zalloc_consistent(enic->pdev,
+ sizeof(union vnic_rss_key),
+ &rss_key_buf_pa);
if (!rss_key_buf_va)
return -ENOMEM;
- memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
-
+ netdev_rss_key_fill(rss_key, ENIC_RSS_LEN);
+ for (i = 0; i < ENIC_RSS_LEN; i++) {
+ kidx = i / ENIC_RSS_BYTES_PER_KEY;
+ bidx = i % ENIC_RSS_BYTES_PER_KEY;
+ rss_key_buf_va->key[kidx].b[bidx] = rss_key[i];
+ }
spin_lock_bh(&enic->devcmd_lock);
err = enic_set_rss_key(enic,
rss_key_buf_pa,
--git a/drivers/net/ethernet/cisco/enic/vnic_rss.h b/drivers/net/ethernet/cisco/enic/vnic_rss.h
index fa421baf45b87eadbf5857843869f1bbcabcdb08..881fa18542b382bc52e222dc4ff47114d052fb00 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_rss.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_rss.h
@@ -20,11 +20,16 @@
#define _VNIC_RSS_H_
/* RSS key array */
+
+#define ENIC_RSS_BYTES_PER_KEY 10
+#define ENIC_RSS_KEYS 4
+#define ENIC_RSS_LEN (ENIC_RSS_BYTES_PER_KEY * ENIC_RSS_KEYS)
+
union vnic_rss_key {
struct {
- u8 b[10];
+ u8 b[ENIC_RSS_BYTES_PER_KEY];
u8 b_pad[6];
- } key[4];
+ } key[ENIC_RSS_KEYS];
u64 raw[8];
};
^ permalink raw reply related
* Re: [PATCH 0/6] kernel tinification: optionally compile out splice family of syscalls (splice, vmsplice, tee and sendfile)
From: Josh Triplett @ 2014-11-23 19:43 UTC (permalink / raw)
To: David Miller
Cc: pieter-qeJ+1H9vRZbz+pZb47iToQ,
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, jlayton-vpEMnDpepFuMZCB2o+C8xQ,
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: <20141123.134623.2061031332250984539.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
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.)
Given the requirements of running a file server in the kernel, I'd
expect CONFIG_NFSD to end up with several more selects of optional
functionality in the future. It seems rather likely that the average
embedded system will be compiling out NFS. :)
Also, this patch series compiles out splice and sendfile, including
several *users* of sendpage; it doesn't compile out the sendpage
support/infrastructure itself.
- Josh Triplett
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox