Netdev List
 help / color / mirror / Atom feed
* Re: Why do we use RX queue mapping for TX?
From: Eric Dumazet @ 2015-02-18 23:14 UTC (permalink / raw)
  To: Cong Wang; +Cc: David S. Miller, netdev
In-Reply-To: <CAHA+R7OVHgwQBM200UZDKiw5eypuzhWj=B4E3MRkOK3yViZDCQ@mail.gmail.com>

On Wed, 2015-02-18 at 14:11 -0800, Cong Wang wrote:
> On Wed, Feb 18, 2015 at 1:18 PM, Cong Wang <cwang@twopensource.com> wrote:
> >
> > 2) This breaks the queue mapping specified by an skbedit action,
> > since for TX queues the index starts with 0 while for RX it starts with 1
> > (for some reason I don't see yet). There is at least a mismatch.
> 
> So queue 0 is reserved for TX, at least for bonding queue mapping.

It seems you missed that bonding ndo_select_queue() is rather special.

^ permalink raw reply

* [PATCH next v5 6/6] bonding: Implement user key part of port_key in an AD system.
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

The port key has three components - user-key, speed-part, and duplex-part.
The LSBit is for the duplex-part, next 5 bits are for the speed while the
remaining 10 bits are the user defined key bits. Get these 10 bits
from the user-space (through the SysFs interface) and use it to form the
admin port-key. Allowed range for the user-key is 0 - 1023 (10 bits). If
it is not provided then use zero for the user-key-bits (default).

It can set using following example code -

   # modprobe bonding mode=4
   # usr_port_key=$(( RANDOM & 0x3FF ))
   # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key
   # echo +eth1 > /sys/class/net/bond0/bonding/slaves
   ...
   # ip link set bond0 up

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
  Initial version
v2:
  Renamed ad_actor_user_port_key ad_user_port_key
v3-v4:
  Rebase
v5:
  Cosmetic changes

 Documentation/networking/bonding.txt | 63 ++++++++++++++++++++++++++++++++++++
 drivers/net/bonding/bond_3ad.c       | 14 ++++----
 drivers/net/bonding/bond_main.c      | 10 ++++++
 drivers/net/bonding/bond_options.c   | 26 +++++++++++++++
 drivers/net/bonding/bond_sysfs.c     | 15 +++++++++
 include/net/bond_options.h           |  1 +
 include/net/bonding.h                |  1 +
 7 files changed, 123 insertions(+), 7 deletions(-)

diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 2c197b68baf0..334b49ef02d1 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -51,6 +51,7 @@ Table of Contents
 3.4	Configuring Bonding Manually via Sysfs
 3.5	Configuration with Interfaces Support
 3.6	Overriding Configuration for Special Cases
+3.7 Configuring LACP for 802.3ad mode in a more secure way
 
 4. Querying Bonding Configuration
 4.1	Bonding Configuration
@@ -241,6 +242,21 @@ ad_select
 
 	This option was added in bonding version 3.4.0.
 
+ad_user_port_key
+
+	In an AD system, the port-key has three parts as shown below -
+
+	   Bits   Use
+	   00     Duplex
+	   01-05  Speed
+	   06-15  User-defined
+
+	This defines the upper 10 bits of the port key. The values can be
+	from 0 - 1023. If not given, the system defaults to 0.
+
+	This parameter has effect only in 802.3ad mode and is available through
+	SysFs interface.
+
 all_slaves_active
 
 	Specifies that duplicate frames (received on inactive ports) should be
@@ -1643,6 +1659,53 @@ output port selection.
 This feature first appeared in bonding driver version 3.7.0 and support for
 output slave selection was limited to round-robin and active-backup modes.
 
+3.7 Configuring LACP for 802.3ad mode in a more secure way
+----------------------------------------------------------
+
+When using 802.3ad bonding mode, the Actor (host) and Partner (switch)
+exchange LACPDUs.  These LACPDUs cannot be sniffed, because they are
+destined to link local mac addresses (which switches/bridges are not
+supposed to forward).  However, most of the values are easily predictable
+or are simply the machine's MAC address (which is trivially known to all
+other hosts in the same L2).  This implies that other machines in the L2
+domain can spoof LACPDU packets from other hosts to the switch and potentially
+cause mayhem by joining (from the point of view of the switch) another
+machine's aggregate, thus receiving a portion of that hosts incoming
+traffic and / or spoofing traffic from that machine themselves (potentially
+even successfully terminating some portion of flows). Though this is not
+a likely scenario, one could avoid this possibility by simply configuring
+few bonding parameters:
+
+   (a) ad_actor_system : You can set a random mac-address that can be used for
+       these LACPDU exchanges. The value can not be either NULL or Multicast.
+       Also it's preferable to set the local-admin bit. Following shell code
+       generates a random mac-address as described above.
+
+       # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
+                                $(( (RANDOM & 0xFE) | 0x02 )) \
+                                $(( RANDOM & 0xFF )) \
+                                $(( RANDOM & 0xFF )) \
+                                $(( RANDOM & 0xFF )) \
+                                $(( RANDOM & 0xFF )) \
+                                $(( RANDOM & 0xFF )))
+       # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system
+
+   (b) ad_actor_sys_prio : Randomize the system priority. The default value
+       is 65535, but system can take the value from 1 - 65535. Following shell
+       code generates random priority and sets it.
+
+       # sys_prio=$(( 1 + RANDOM + RANDOM ))
+       # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio
+
+   (c) ad_user_port_key : Use the user portion of the port-key. The default
+       keeps this empty. These are the upper 10 bits of the port-key and value
+       ranges from 0 - 1023. Following shell code generates these 10 bits and
+       sets it.
+
+       # usr_port_key=$(( RANDOM & 0x3FF ))
+       # echo $usr_port_key > /sys/class/net/bond0/bonding/ad_user_port_key
+
+
 4 Querying Bonding Configuration
 =================================
 
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index e97b20954ab9..5b68db4d8bd5 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -75,10 +75,10 @@
 /* Port Key definitions
  * key is determined according to the link speed, duplex and
  * user key (which is yet not supported)
- * --------------------------------------------------------------
- * Port key :	| User key	| Speed		| Duplex	|
- * --------------------------------------------------------------
- * 16		  6		  1		  0
+ *           --------------------------------------------------------------
+ * Port key  | User key (10 bits)           | Speed (5 bits)      | Duplex|
+ *           --------------------------------------------------------------
+ *           |15                           6|5                   1|0
  */
 #define  AD_DUPLEX_KEY_MASKS    0x1
 #define  AD_SPEED_KEY_MASKS     0x3E
@@ -1955,10 +1955,10 @@ void bond_3ad_bind_slave(struct slave *slave)
 
 		port->slave = slave;
 		port->actor_port_number = SLAVE_AD_INFO(slave)->id;
-		/* key is determined according to the link speed, duplex and user key(which
-		 * is yet not supported)
+		/* key is determined according to the link speed, duplex and
+		 * user key
 		 */
-		port->actor_admin_port_key = 0;
+		port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
 		port->actor_admin_port_key |= __get_duplex(port);
 		port->actor_admin_port_key |= (__get_link_speed(port) << 1);
 		port->actor_oper_port_key = port->actor_admin_port_key;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 30ad9e68fd3b..d7a8e4113009 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4139,6 +4139,7 @@ static int bond_check_params(struct bond_params *params)
 	const struct bond_opt_value *valptr;
 	int arp_all_targets_value;
 	u16 ad_actor_sys_prio = 0;
+	u16 ad_user_port_key = 0;
 
 	/* Convert string parameters. */
 	if (mode) {
@@ -4443,6 +4444,14 @@ static int bond_check_params(struct bond_params *params)
 			return -EINVAL;
 		}
 		ad_actor_sys_prio = valptr->value;
+
+		valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY),
+					&newval);
+		if (!valptr) {
+			pr_err("Error: No ad_user_port_key default value");
+			return -EINVAL;
+		}
+		ad_user_port_key = valptr->value;
 	}
 
 	if (lp_interval == 0) {
@@ -4475,6 +4484,7 @@ static int bond_check_params(struct bond_params *params)
 	params->tlb_dynamic_lb = 1; /* Default value */
 	params->ad_actor_sys_prio = ad_actor_sys_prio;
 	eth_zero_addr(params->ad_actor_system);
+	params->ad_user_port_key = ad_user_port_key;
 	if (packets_per_slave > 0) {
 		params->reciprocal_packets_per_slave =
 			reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index f2c011b3ea33..eb0a8e9fafe7 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -74,6 +74,8 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
 static int bond_option_ad_actor_system_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+				  const struct bond_opt_value *newval);
 
 
 static const struct bond_opt_value bond_mode_tbl[] = {
@@ -196,6 +198,12 @@ static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
 	{ NULL,      -1,    0},
 };
 
+static const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
+	{ "minval",  0,     BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
+	{ "maxval",  1023,  BOND_VALFLAG_MAX},
+	{ NULL,      -1,    0},
+};
+
 static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 	[BOND_OPT_MODE] = {
 		.id = BOND_OPT_MODE,
@@ -405,6 +413,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 		.flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN,
 		.set = bond_option_ad_actor_system_set,
 	},
+	[BOND_OPT_AD_USER_PORT_KEY] = {
+		.id = BOND_OPT_AD_USER_PORT_KEY,
+		.name = "ad_user_port_key",
+		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+		.flags = BOND_OPTFLAG_IFDOWN,
+		.values = bond_ad_user_port_key_tbl,
+		.set = bond_option_ad_user_port_key_set,
+	}
 };
 
 /* Searches for an option by name */
@@ -1405,3 +1421,13 @@ static int bond_option_ad_actor_system_set(struct bonding *bond,
 
 	return 0;
 }
+
+static int bond_option_ad_user_port_key_set(struct bonding *bond,
+					    const struct bond_opt_value *newval)
+{
+	netdev_info(bond->dev, "Setting ad_user_port_key to (%llu)\n",
+		    newval->value);
+
+	bond->params.ad_user_port_key = newval->value;
+	return 0;
+}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index efa994243a2d..a6950647d99d 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -720,6 +720,20 @@ static ssize_t bonding_show_ad_actor_system(struct device *d,
 static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR,
 		   bonding_show_ad_actor_system, bonding_sysfs_store_option);
 
+static ssize_t bonding_show_ad_user_port_key(struct device *d,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	if (BOND_MODE(bond) == BOND_MODE_8023AD)
+		return sprintf(buf, "%hu\n", bond->params.ad_user_port_key);
+
+	return 0;
+}
+static DEVICE_ATTR(ad_user_port_key, S_IRUGO | S_IWUSR,
+		   bonding_show_ad_user_port_key, bonding_sysfs_store_option);
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -755,6 +769,7 @@ static struct attribute *per_bond_attrs[] = {
 	&dev_attr_tlb_dynamic_lb.attr,
 	&dev_attr_ad_actor_sys_prio.attr,
 	&dev_attr_ad_actor_system.attr,
+	&dev_attr_ad_user_port_key.attr,
 	NULL,
 };
 
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index eeeefa1d3cd8..c28aca25320e 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -65,6 +65,7 @@ enum {
 	BOND_OPT_TLB_DYNAMIC_LB,
 	BOND_OPT_AD_ACTOR_SYS_PRIO,
 	BOND_OPT_AD_ACTOR_SYSTEM,
+	BOND_OPT_AD_USER_PORT_KEY,
 	BOND_OPT_LAST
 };
 
diff --git a/include/net/bonding.h b/include/net/bonding.h
index f24f9862cea9..0ac45b4f7f2a 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -144,6 +144,7 @@ struct bond_params {
 	int tlb_dynamic_lb;
 	struct reciprocal_value reciprocal_packets_per_slave;
 	u16 ad_actor_sys_prio;
+	u16 ad_user_port_key;
 	u8 ad_actor_system[ETH_ALEN];
 };
 
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* [PATCH next v5 5/6] bonding: Allow userspace to set actors' macaddr in an AD-system.
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

In an AD system, the communication between actor and partner is the
business between these two entities. In the current setup anyone on the
same L2 can "guess" the LACPDU contents and then possibly send the
spoofed LACPDUs and trick the partner causing connectivity issues for
the AD system. This patch allows to use a random mac-address obscuring
it's identity making it harder for someone in the L2 is do the same thing.

This patch allows user-space to choose the mac-address for the AD-system.
This mac-address can not be NULL or a Multicast. If the mac-address is set
from user-space; kernel will honor it and will not overwrite it. In the
absence (value from user space); the logic will default to using the
masters' mac as the mac-address for the AD-system.

It can be set using example code below -

   # modprobe bonding mode=4
   # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \
                    $(( (RANDOM & 0xFE) | 0x02 )) \
                    $(( RANDOM & 0xFF )) \
                    $(( RANDOM & 0xFF )) \
                    $(( RANDOM & 0xFF )) \
                    $(( RANDOM & 0xFF )) \
                    $(( RANDOM & 0xFF )))
   # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system
   # echo +eth1 > /sys/class/net/bond0/bonding/slaves
   ...
   # ip link set bond0 up

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
  Initial version
v2:
  Renamed ad_actor_system_mac_address to ad_actor_system
v3:
  Fixed commit message.
v4:
  Rebase
v5:
  Cosmetic changes

 Documentation/networking/bonding.txt | 12 ++++++++++++
 drivers/net/bonding/bond_3ad.c       |  7 ++++++-
 drivers/net/bonding/bond_main.c      |  1 +
 drivers/net/bonding/bond_options.c   | 29 +++++++++++++++++++++++++++++
 drivers/net/bonding/bond_procfs.c    |  6 ++++++
 drivers/net/bonding/bond_sysfs.c     | 15 +++++++++++++++
 include/net/bond_options.h           |  1 +
 include/net/bonding.h                |  1 +
 8 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 34946115acec..2c197b68baf0 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -187,6 +187,18 @@ ad_actor_sys_prio
 	This parameter has effect only in 802.3ad mode and is available through
 	SysFs interface.
 
+ad_actor_system
+
+	In an AD system, this specifies the mac-address for the actor in
+	protocol packet exchanges (LACPDUs). The value cannot be NULL or
+	multicast. It is preferred to have the local-admin bit set for this
+	mac but driver does not enforce it. If the value is not given then
+	system defaults to using the masters' mac address as actors' system
+	address.
+
+	This parameter has effect only in 802.3ad mode and is available through
+	SysFs interface.
+
 ad_select
 
 	Specifies the 802.3ad aggregation selection logic to use.  The
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index bb2a00b02157..e97b20954ab9 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1914,7 +1914,12 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
 
 		BOND_AD_INFO(bond).system.sys_priority =
 			bond->params.ad_actor_sys_prio;
-		BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
+		if (is_zero_ether_addr(bond->params.ad_actor_system))
+			BOND_AD_INFO(bond).system.sys_mac_addr =
+			    *((struct mac_addr *)bond->dev->dev_addr);
+		else
+			BOND_AD_INFO(bond).system.sys_mac_addr =
+			    *((struct mac_addr *)bond->params.ad_actor_system);
 
 		/* initialize how many times this module is called in one
 		 * second (should be about every 100ms)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index bf30a973e51c..30ad9e68fd3b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4474,6 +4474,7 @@ static int bond_check_params(struct bond_params *params)
 	params->packets_per_slave = packets_per_slave;
 	params->tlb_dynamic_lb = 1; /* Default value */
 	params->ad_actor_sys_prio = ad_actor_sys_prio;
+	eth_zero_addr(params->ad_actor_system);
 	if (packets_per_slave > 0) {
 		params->reciprocal_packets_per_slave =
 			reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 05d5e735eaec..f2c011b3ea33 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -72,6 +72,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
 static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+				  const struct bond_opt_value *newval);
 
 
 static const struct bond_opt_value bond_mode_tbl[] = {
@@ -396,6 +398,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 		.values = bond_ad_actor_sys_prio_tbl,
 		.set = bond_option_ad_actor_sys_prio_set,
 	},
+	[BOND_OPT_AD_ACTOR_SYSTEM] = {
+		.id = BOND_OPT_AD_ACTOR_SYSTEM,
+		.name = "ad_actor_system",
+		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+		.flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN,
+		.set = bond_option_ad_actor_system_set,
+	},
 };
 
 /* Searches for an option by name */
@@ -1376,3 +1385,23 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
 	bond->params.ad_actor_sys_prio = newval->value;
 	return 0;
 }
+
+static int bond_option_ad_actor_system_set(struct bonding *bond,
+					    const struct bond_opt_value *newval)
+{
+	u8 macaddr[ETH_ALEN];
+	int i;
+
+	i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+		   &macaddr[0], &macaddr[1], &macaddr[2],
+		   &macaddr[3], &macaddr[4], &macaddr[5]);
+
+	if (i != ETH_ALEN || !is_valid_ether_addr(macaddr)) {
+		netdev_err(bond->dev, "Invalid MAC address.\n");
+		return -EINVAL;
+	}
+
+	ether_addr_copy(bond->params.ad_actor_system, macaddr);
+
+	return 0;
+}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 282cbd9fde63..c949bab6b2fc 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -136,6 +136,8 @@ static void bond_info_show_master(struct seq_file *seq)
 			   optval->string);
 		seq_printf(seq, "System priority: %d\n",
 				BOND_AD_INFO(bond).system.sys_priority);
+		seq_printf(seq, "System MAC address: %pM\n",
+				&BOND_AD_INFO(bond).system.sys_mac_addr);
 
 		if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
 			seq_printf(seq, "bond %s has no active aggregator\n",
@@ -198,6 +200,8 @@ static void bond_info_show_slave(struct seq_file *seq,
 			seq_puts(seq, "details actor lacp pdu:\n");
 			seq_printf(seq, "    system priority: %d\n",
 				   port->actor_system_priority);
+			seq_printf(seq, "    system mac address: %pM\n",
+				   &port->actor_system);
 			seq_printf(seq, "    port key: %d\n",
 				   port->actor_oper_port_key);
 			seq_printf(seq, "    port priority: %d\n",
@@ -210,6 +214,8 @@ static void bond_info_show_slave(struct seq_file *seq,
 			seq_puts(seq, "details partner lacp pdu:\n");
 			seq_printf(seq, "    system priority: %d\n",
 				   port->partner_oper.system_priority);
+			seq_printf(seq, "    system mac address: %pM\n",
+				   &port->partner_oper.system);
 			seq_printf(seq, "    oper key: %d\n",
 				   port->partner_oper.key);
 			seq_printf(seq, "    port priority: %d\n",
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 1a4a591a58c9..efa994243a2d 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -706,6 +706,20 @@ static ssize_t bonding_show_ad_actor_sys_prio(struct device *d,
 static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR,
 		   bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option);
 
+static ssize_t bonding_show_ad_actor_system(struct device *d,
+						 struct device_attribute *attr,
+						 char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	if (BOND_MODE(bond) == BOND_MODE_8023AD)
+		return sprintf(buf, "%pM\n", bond->params.ad_actor_system);
+
+	return 0;
+}
+static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR,
+		   bonding_show_ad_actor_system, bonding_sysfs_store_option);
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -740,6 +754,7 @@ static struct attribute *per_bond_attrs[] = {
 	&dev_attr_packets_per_slave.attr,
 	&dev_attr_tlb_dynamic_lb.attr,
 	&dev_attr_ad_actor_sys_prio.attr,
+	&dev_attr_ad_actor_system.attr,
 	NULL,
 };
 
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index 894002a2620f..eeeefa1d3cd8 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -64,6 +64,7 @@ enum {
 	BOND_OPT_SLAVES,
 	BOND_OPT_TLB_DYNAMIC_LB,
 	BOND_OPT_AD_ACTOR_SYS_PRIO,
+	BOND_OPT_AD_ACTOR_SYSTEM,
 	BOND_OPT_LAST
 };
 
diff --git a/include/net/bonding.h b/include/net/bonding.h
index cb4587f6516e..f24f9862cea9 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -144,6 +144,7 @@ struct bond_params {
 	int tlb_dynamic_lb;
 	struct reciprocal_value reciprocal_packets_per_slave;
 	u16 ad_actor_sys_prio;
+	u8 ad_actor_system[ETH_ALEN];
 };
 
 struct bond_parm_tbl {
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* [PATCH next v5 4/6] bonding: Allow userspace to set actors' system_priority in AD system
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

This patch allows user to randomize the system-priority in an ad-system.
The allowed range is 1 - 0xFFFF while default value is 0xFFFF. If user
does not specify this value, the system defaults to 0xFFFF, which is
what it was before this patch.

Following example code could set the value -
    # modprobe bonding mode=4
    # sys_prio=$(( 1 + RANDOM + RANDOM ))
    # echo $sys_prio > /sys/class/net/bond0/bonding/ad_actor_sys_prio
    # echo +eth1 > /sys/class/net/bond0/bonding/slaves
    ...
    # ip link set bond0 up

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
  Initial version
v2:
  Rename ad_actor_system_priority to ad_actor_sys_prio
v3-v4:
  Rebase
v5:
  Cosmetic changes

 Documentation/networking/bonding.txt |  9 +++++++++
 drivers/net/bonding/bond_3ad.c       |  5 ++++-
 drivers/net/bonding/bond_main.c      | 14 ++++++++++++++
 drivers/net/bonding/bond_options.c   | 29 ++++++++++++++++++++++++++++-
 drivers/net/bonding/bond_procfs.c    |  2 ++
 drivers/net/bonding/bond_sysfs.c     | 15 +++++++++++++++
 include/net/bond_options.h           |  1 +
 include/net/bonding.h                |  1 +
 8 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 83bf4986baea..34946115acec 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -178,6 +178,15 @@ active_slave
 	active slave, or the empty string if there is no active slave or
 	the current mode does not use an active slave.
 
+ad_actor_sys_prio
+
+	In an AD system, this specifies the system priority. The allowed range
+	is 1 - 65535. If the value is not specified, it takes 65535 as the
+	default value.
+
+	This parameter has effect only in 802.3ad mode and is available through
+	SysFs interface.
+
 ad_select
 
 	Specifies the 802.3ad aggregation selection logic to use.  The
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 94f6ae38def2..bb2a00b02157 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1912,7 +1912,8 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
 
 		BOND_AD_INFO(bond).aggregator_identifier = 0;
 
-		BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
+		BOND_AD_INFO(bond).system.sys_priority =
+			bond->params.ad_actor_sys_prio;
 		BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
 
 		/* initialize how many times this module is called in one
@@ -1963,6 +1964,8 @@ void bond_3ad_bind_slave(struct slave *slave)
 			port->sm_vars &= ~AD_PORT_LACP_ENABLED;
 		/* actor system is the bond's system */
 		port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
+		port->actor_system_priority =
+		    BOND_AD_INFO(bond).system.sys_priority;
 		/* tx timer(to verify that no more than MAX_TX_IN_SECOND
 		 * lacpdu's are sent in one second)
 		 */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 63e6c0dbe7b3..bf30a973e51c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4138,6 +4138,7 @@ static int bond_check_params(struct bond_params *params)
 	struct bond_opt_value newval;
 	const struct bond_opt_value *valptr;
 	int arp_all_targets_value;
+	u16 ad_actor_sys_prio = 0;
 
 	/* Convert string parameters. */
 	if (mode) {
@@ -4432,6 +4433,18 @@ static int bond_check_params(struct bond_params *params)
 		fail_over_mac_value = BOND_FOM_NONE;
 	}
 
+	if (bond_mode == BOND_MODE_8023AD) {
+		bond_opt_initstr(&newval, "default");
+		valptr = bond_opt_parse(
+				bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO),
+					     &newval);
+		if (!valptr) {
+			pr_err("Error: No ad_actor_sys_prio default value");
+			return -EINVAL;
+		}
+		ad_actor_sys_prio = valptr->value;
+	}
+
 	if (lp_interval == 0) {
 		pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
 			INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
@@ -4460,6 +4473,7 @@ static int bond_check_params(struct bond_params *params)
 	params->lp_interval = lp_interval;
 	params->packets_per_slave = packets_per_slave;
 	params->tlb_dynamic_lb = 1; /* Default value */
+	params->ad_actor_sys_prio = ad_actor_sys_prio;
 	if (packets_per_slave > 0) {
 		params->reciprocal_packets_per_slave =
 			reciprocal_value(packets_per_slave);
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 4df28943d222..05d5e735eaec 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -70,6 +70,8 @@ static int bond_option_slaves_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
 static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
 				  const struct bond_opt_value *newval);
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+				  const struct bond_opt_value *newval);
 
 
 static const struct bond_opt_value bond_mode_tbl[] = {
@@ -186,6 +188,12 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
 	{ NULL,  -1, 0}
 };
 
+static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
+	{ "minval",  1,     BOND_VALFLAG_MIN},
+	{ "maxval",  65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
+	{ NULL,      -1,    0},
+};
+
 static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 	[BOND_OPT_MODE] = {
 		.id = BOND_OPT_MODE,
@@ -379,7 +387,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 		.values = bond_tlb_dynamic_lb_tbl,
 		.flags = BOND_OPTFLAG_IFDOWN,
 		.set = bond_option_tlb_dynamic_lb_set,
-	}
+	},
+	[BOND_OPT_AD_ACTOR_SYS_PRIO] = {
+		.id = BOND_OPT_AD_ACTOR_SYS_PRIO,
+		.name = "ad_actor_sys_prio",
+		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
+		.flags = BOND_OPTFLAG_IFDOWN,
+		.values = bond_ad_actor_sys_prio_tbl,
+		.set = bond_option_ad_actor_sys_prio_set,
+	},
 };
 
 /* Searches for an option by name */
@@ -1349,3 +1365,14 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
 
 	return 0;
 }
+
+
+static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
+					    const struct bond_opt_value *newval)
+{
+	netdev_info(bond->dev, "Setting ad_actor_sys_prio to (%llu)\n",
+		    newval->value);
+
+	bond->params.ad_actor_sys_prio = newval->value;
+	return 0;
+}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 573c4e43210c..282cbd9fde63 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -134,6 +134,8 @@ static void bond_info_show_master(struct seq_file *seq)
 					  bond->params.ad_select);
 		seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
 			   optval->string);
+		seq_printf(seq, "System priority: %d\n",
+				BOND_AD_INFO(bond).system.sys_priority);
 
 		if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
 			seq_printf(seq, "bond %s has no active aggregator\n",
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 7e9e151d4d61..1a4a591a58c9 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -692,6 +692,20 @@ static ssize_t bonding_show_packets_per_slave(struct device *d,
 static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR,
 		   bonding_show_packets_per_slave, bonding_sysfs_store_option);
 
+static ssize_t bonding_show_ad_actor_sys_prio(struct device *d,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct bonding *bond = to_bond(d);
+
+	if (BOND_MODE(bond) == BOND_MODE_8023AD)
+		return sprintf(buf, "%hu\n", bond->params.ad_actor_sys_prio);
+
+	return 0;
+}
+static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR,
+		   bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option);
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -725,6 +739,7 @@ static struct attribute *per_bond_attrs[] = {
 	&dev_attr_lp_interval.attr,
 	&dev_attr_packets_per_slave.attr,
 	&dev_attr_tlb_dynamic_lb.attr,
+	&dev_attr_ad_actor_sys_prio.attr,
 	NULL,
 };
 
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index ea6546d2c946..894002a2620f 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -63,6 +63,7 @@ enum {
 	BOND_OPT_LP_INTERVAL,
 	BOND_OPT_SLAVES,
 	BOND_OPT_TLB_DYNAMIC_LB,
+	BOND_OPT_AD_ACTOR_SYS_PRIO,
 	BOND_OPT_LAST
 };
 
diff --git a/include/net/bonding.h b/include/net/bonding.h
index fda6feeb6c1f..cb4587f6516e 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -143,6 +143,7 @@ struct bond_params {
 	int packets_per_slave;
 	int tlb_dynamic_lb;
 	struct reciprocal_value reciprocal_packets_per_slave;
+	u16 ad_actor_sys_prio;
 };
 
 struct bond_parm_tbl {
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* [PATCH next v5 3/6] bonding: Implement port churn-machine (AD standard 43.4.17).
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

The Churn Detection machines detect the situation where a port is operable,
but the Actor and Partner have not attached the link to an Aggregator and
brought the link into operation within a bound time period. Under normal
operation of the LACP, agreement between Actor and Partner should be reached
very rapidly. Continued failure to reach agreement can be symptomatic of
device failure.

Actor-churn-detection state-machine
===================================

BEGIN=True + PortEnable=False
           |
           v
 +------------------------+   ActorPort.Sync=True  +------------------+
 |   ACTOR_CHURN_MONITOR  | ---------------------> |  NO_ACTOR_CHURN  |
 |========================|                        |==================|
 |    ActorChurn=False    |  ActorPort.Sync=False  | ActorChurn=False |
 | ActorChurn.Timer=Start | <--------------------- |                  |
 +------------------------+                        +------------------+
           |                                                ^
           |                                                |
  ActorChurn.Timer=Expired                                  |
           |                                       ActorPort.Sync=True
           |                                                |
           |                +-----------------+             |
           |                |   ACTOR_CHURN   |             |
           |                |=================|             |
           +--------------> | ActorChurn=True | ------------+
                            |                 |
                            +-----------------+

Similar for the Partner-churn-detection.

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
  Initial version
v2-v4:
  Rebase
v5:
  Cosmetic changes

 drivers/net/bonding/bond_3ad.c    | 56 +++++++++++++++++++++++++++++++++++++--
 drivers/net/bonding/bond_procfs.c | 41 +++++++++++++++++++++++++---
 include/net/bond_3ad.h            | 29 ++++++++++++++++++++
 3 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 9b436696b95e..94f6ae38def2 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -38,6 +38,7 @@
 #define AD_STANDBY                 0x2
 #define AD_MAX_TX_IN_SECOND        3
 #define AD_COLLECTOR_MAX_DELAY     0
+#define AD_MONITOR_CHURNED         0x1000
 
 /* Timer definitions (43.4.4 in the 802.3ad standard) */
 #define AD_FAST_PERIODIC_TIME      1
@@ -1013,16 +1014,19 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 	/* check if state machine should change state */
 
 	/* first, check if port was reinitialized */
-	if (port->sm_vars & AD_PORT_BEGIN)
+	if (port->sm_vars & AD_PORT_BEGIN) {
 		port->sm_rx_state = AD_RX_INITIALIZE;
+		port->sm_vars |= AD_MONITOR_CHURNED;
 	/* check if port is not enabled */
-	else if (!(port->sm_vars & AD_PORT_BEGIN)
+	} else if (!(port->sm_vars & AD_PORT_BEGIN)
 		 && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
 		port->sm_rx_state = AD_RX_PORT_DISABLED;
 	/* check if new lacpdu arrived */
 	else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) ||
 		 (port->sm_rx_state == AD_RX_DEFAULTED) ||
 		 (port->sm_rx_state == AD_RX_CURRENT))) {
+		if (port->sm_rx_state != AD_RX_CURRENT)
+			port->sm_vars |= AD_MONITOR_CHURNED;
 		port->sm_rx_timer_counter = 0;
 		port->sm_rx_state = AD_RX_CURRENT;
 	} else {
@@ -1100,9 +1104,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 			 */
 			port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
 			port->sm_vars &= ~AD_PORT_MATCHED;
+			port->partner_oper.port_state |= AD_STATE_LACP_TIMEOUT;
 			port->partner_oper.port_state |= AD_STATE_LACP_ACTIVITY;
 			port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
 			port->actor_oper_port_state |= AD_STATE_EXPIRED;
+			port->sm_vars |= AD_MONITOR_CHURNED;
 			break;
 		case AD_RX_DEFAULTED:
 			__update_default_selected(port);
@@ -1131,6 +1137,44 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 	}
 }
 
+/* ad_churn_machine - handle port churn's state machine
+ * @port: the port we're looking at
+ *
+ */
+static void ad_churn_machine(struct port *port)
+{
+	if (port->sm_vars & AD_MONITOR_CHURNED) {
+		port->sm_vars &= ~AD_MONITOR_CHURNED;
+		port->sm_churn_actor_state = AD_CHURN_MONITOR;
+		port->sm_churn_partner_state = AD_CHURN_MONITOR;
+		port->sm_churn_actor_timer_counter =
+			__ad_timer_to_ticks(AD_ACTOR_CHURN_TIMER, 0);
+		 port->sm_churn_partner_timer_counter =
+			 __ad_timer_to_ticks(AD_PARTNER_CHURN_TIMER, 0);
+		return;
+	}
+	if (port->sm_churn_actor_timer_counter &&
+	    !(--port->sm_churn_actor_timer_counter) &&
+	    port->sm_churn_actor_state == AD_CHURN_MONITOR) {
+		if (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION) {
+			port->sm_churn_actor_state = AD_NO_CHURN;
+		} else {
+			port->churn_actor_count++;
+			port->sm_churn_actor_state = AD_CHURN;
+		}
+	}
+	if (port->sm_churn_partner_timer_counter &&
+	    !(--port->sm_churn_partner_timer_counter) &&
+	    port->sm_churn_partner_state == AD_CHURN_MONITOR) {
+		if (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) {
+			port->sm_churn_partner_state = AD_NO_CHURN;
+		} else {
+			port->churn_partner_count++;
+			port->sm_churn_partner_state = AD_CHURN;
+		}
+	}
+}
+
 /**
  * ad_tx_machine - handle a port's tx state machine
  * @port: the port we're looking at
@@ -1745,6 +1789,13 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
 		port->next_port_in_aggregator = NULL;
 		port->transaction_id = 0;
 
+		port->sm_churn_actor_timer_counter = 0;
+		port->sm_churn_actor_state = 0;
+		port->churn_actor_count = 0;
+		port->sm_churn_partner_timer_counter = 0;
+		port->sm_churn_partner_state = 0;
+		port->churn_partner_count = 0;
+
 		memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu));
 	}
 }
@@ -2164,6 +2215,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
 		ad_port_selection_logic(port, &update_slave_arr);
 		ad_mux_machine(port, &update_slave_arr);
 		ad_tx_machine(port);
+		ad_churn_machine(port);
 
 		/* turn off the BEGIN bit, since we already handled it */
 		if (port->sm_vars & AD_PORT_BEGIN)
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 976f5ad2a0f2..573c4e43210c 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -178,14 +178,47 @@ static void bond_info_show_slave(struct seq_file *seq,
 	seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr);
 
 	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
-		const struct aggregator *agg
-			= SLAVE_AD_INFO(slave)->port.aggregator;
+		const struct port *port = &SLAVE_AD_INFO(slave)->port;
+		const struct aggregator *agg = port->aggregator;
 
-		if (agg)
+		if (agg) {
 			seq_printf(seq, "Aggregator ID: %d\n",
 				   agg->aggregator_identifier);
-		else
+			seq_printf(seq, "Actor Churn State: %s\n",
+				   bond_3ad_churn_desc(port->sm_churn_actor_state));
+			seq_printf(seq, "Partner Churn State: %s\n",
+				   bond_3ad_churn_desc(port->sm_churn_partner_state));
+			seq_printf(seq, "Actor Churned Count: %d\n",
+				   port->churn_actor_count);
+			seq_printf(seq, "Partner Churned Count: %d\n",
+				   port->churn_partner_count);
+
+			seq_puts(seq, "details actor lacp pdu:\n");
+			seq_printf(seq, "    system priority: %d\n",
+				   port->actor_system_priority);
+			seq_printf(seq, "    port key: %d\n",
+				   port->actor_oper_port_key);
+			seq_printf(seq, "    port priority: %d\n",
+				   port->actor_port_priority);
+			seq_printf(seq, "    port number: %d\n",
+				   port->actor_port_number);
+			seq_printf(seq, "    port state: %d\n",
+				   port->actor_oper_port_state);
+
+			seq_puts(seq, "details partner lacp pdu:\n");
+			seq_printf(seq, "    system priority: %d\n",
+				   port->partner_oper.system_priority);
+			seq_printf(seq, "    oper key: %d\n",
+				   port->partner_oper.key);
+			seq_printf(seq, "    port priority: %d\n",
+				   port->partner_oper.port_priority);
+			seq_printf(seq, "    port number: %d\n",
+				   port->partner_oper.port_number);
+			seq_printf(seq, "    port state: %d\n",
+				   port->partner_oper.port_state);
+		} else {
 			seq_puts(seq, "Aggregator ID: N/A\n");
+		}
 	}
 	seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
 }
diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h
index f04cdbb7848e..22ac75dd8bd5 100644
--- a/include/net/bond_3ad.h
+++ b/include/net/bond_3ad.h
@@ -82,6 +82,13 @@ typedef enum {
 	AD_TRANSMIT		/* tx Machine */
 } tx_states_t;
 
+/* churn machine states(43.4.17 in the 802.3ad standard) */
+typedef enum {
+	 AD_CHURN_MONITOR, /* monitoring for churn */
+	 AD_CHURN,         /* churn detected (error) */
+	 AD_NO_CHURN       /* no churn (no error) */
+} churn_state_t;
+
 /* rx indication types */
 typedef enum {
 	AD_TYPE_LACPDU = 1,	/* type lacpdu */
@@ -229,6 +236,12 @@ typedef struct port {
 	u16 sm_mux_timer_counter;	/* state machine mux timer counter */
 	tx_states_t sm_tx_state;	/* state machine tx state */
 	u16 sm_tx_timer_counter;	/* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
+	u16 sm_churn_actor_timer_counter;
+	u16 sm_churn_partner_timer_counter;
+	u32 churn_actor_count;
+	u32 churn_partner_count;
+	churn_state_t sm_churn_actor_state;
+	churn_state_t sm_churn_partner_state;
 	struct slave *slave;		/* pointer to the bond slave that this port belongs to */
 	struct aggregator *aggregator;	/* pointer to an aggregator that this port related to */
 	struct port *next_port_in_aggregator;	/* Next port on the linked list of the parent aggregator */
@@ -262,6 +275,22 @@ struct ad_slave_info {
 	u16 id;
 };
 
+static inline const char *bond_3ad_churn_desc(churn_state_t state)
+{
+	static const char *const churn_description[] =
+		{ "monitoring",
+		  "churned",
+		  "none",
+		  "unknown"
+		};
+	int max_size = sizeof(churn_description) / sizeof(churn_description[0]);
+
+	if (state >= max_size)
+		state = max_size - 1;
+
+	return churn_description[state];
+}
+
 /* ========== AD Exported functions to the main bonding code ========== */
 void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
 void bond_3ad_bind_slave(struct slave *slave);
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* [PATCH next v5 2/6] bonding: implement bond_poll_controller()
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

This patches implements the poll_controller support for all
bonding driver. If the slaves have poll_controller net_op defined,
this implementation calls them. This is mode agnostic implementation
and iterates through all slaves (based on mode) and calls respective
handler.

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
   Initial version
v2:
   Eliminate bool variable.
v3:
   Rebase
v4:
   Removed 3AD port_operational check
v5:
   Added rtnl protection for bond_for_each_slave()

 drivers/net/bonding/bond_main.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b979c265fc51..63e6c0dbe7b3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -928,6 +928,39 @@ static inline void slave_disable_netpoll(struct slave *slave)
 
 static void bond_poll_controller(struct net_device *bond_dev)
 {
+	struct bonding *bond = netdev_priv(bond_dev);
+	struct slave *slave = NULL;
+	struct list_head *iter;
+	struct ad_info ad_info;
+	struct netpoll_info *ni;
+	const struct net_device_ops *ops;
+
+	if (BOND_MODE(bond) == BOND_MODE_8023AD)
+		if (bond_3ad_get_active_agg_info(bond, &ad_info))
+			return;
+
+	rtnl_lock();
+	bond_for_each_slave(bond, slave, iter) {
+		ops = slave->dev->netdev_ops;
+		if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller)
+			continue;
+
+		if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+			struct aggregator *agg =
+			    SLAVE_AD_INFO(slave)->port.aggregator;
+
+			if (agg &&
+			    agg->aggregator_identifier != ad_info.aggregator_id)
+				continue;
+		}
+
+		ni = rcu_dereference_bh(slave->dev->npinfo);
+		if (down_trylock(&ni->dev_lock))
+			continue;
+		ops->ndo_poll_controller(slave->dev);
+		up(&ni->dev_lock);
+	}
+	rtnl_unlock();
 }
 
 static void bond_netpoll_cleanup(struct net_device *bond_dev)
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* [PATCH next v5 1/6] bonding: Verify RX LACPDU has proper dest mac-addr
From: Mahesh Bandewar @ 2015-02-18 22:31 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico,
	Nikolay Aleksandrov, David Miller
  Cc: Mahesh Bandewar, Maciej Zenczykowski, netdev, Eric Dumazet

The 802.1AX standard states:
"The DA in LACPDUs is the Slow_Protocols_Multicast address."

This patch enforces that and drops LACPDUs with destination MAC
addresses other than Slow_Protocols_Multicast address

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v1:
   Initial version
v2-v5:
   Rebase

 drivers/net/bonding/bond_3ad.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index cfc4a9c1000a..9b436696b95e 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2485,6 +2485,9 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
 	if (skb->protocol != PKT_TYPE_LACPDU)
 		return RX_HANDLER_ANOTHER;
 
+	if (!MAC_ADDRESS_EQUAL(eth_hdr(skb)->h_dest, lacpdu_mcast_addr))
+		return RX_HANDLER_ANOTHER;
+
 	lacpdu = skb_header_pointer(skb, 0, sizeof(_lacpdu), &_lacpdu);
 	if (!lacpdu)
 		return RX_HANDLER_ANOTHER;
-- 
2.2.0.rc0.207.ga3a616c

^ permalink raw reply related

* Re: Why do we use RX queue mapping for TX?
From: Cong Wang @ 2015-02-18 22:11 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev
In-Reply-To: <CAHA+R7PdG+jDqFA1jDFzHtkrxqLEZdtj1w5QyrdYMO4fX6+A1w@mail.gmail.com>

On Wed, Feb 18, 2015 at 1:18 PM, Cong Wang <cwang@twopensource.com> wrote:
>
> 2) This breaks the queue mapping specified by an skbedit action,
> since for TX queues the index starts with 0 while for RX it starts with 1
> (for some reason I don't see yet). There is at least a mismatch.

So queue 0 is reserved for TX, at least for bonding queue mapping.

But for sch_mq, all queues are used, 0 is merely the default one.
This means we should still allow user to specify queue 0 for TX.

We are trying to do queue mapping for containers, queue 0 isn't
special for us at all, therefore I don't see why we should reserve it
at least for hardware TX queues.

*I think* we should use the same strategy for TX queue mapping like
RX queue mapping, where ->queue_mapping = 0 means "not set",
while ->queue_mapping maps to a real queue index starting at 0.
This would also make ->queue_mapping have the same meaning
across RX -> TX if we really need to preserve it.

^ permalink raw reply

* Re: Why do we use RX queue mapping for TX?
From: Cong Wang @ 2015-02-18 21:18 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev
In-Reply-To: <CAHA+R7MXF-KHZ3aeBwwshSYDswKwrjhbMJQ=+Hfj3gZJq70dXQ@mail.gmail.com>

Hi, David

With regarding to the following commit:

commit d5a9e24afb4ab38110ebb777588ea0bd0eacbd0a
Author: David S. Miller <davem@davemloft.net>
Date:   Tue Jan 27 16:22:11 2009 -0800

    net: Allow RX queue selection to seed TX queue hashing.

What's the point of this commit? It looks like it is for routers
where skb->queue_mapping is preserved across forwarding.
Or some software interface, but they usually don't even have
a queue.

But:

1) the incoming interface may not be same with the outgoing
interface, therefore they may not has the same number of queues.
Even if it's the same interface, the number of RX queues doesn't
have to be same with TX queues either.

2) This breaks the queue mapping specified by an skbedit action,
since for TX queues the index starts with 0 while for RX it starts with 1
(for some reason I don't see yet). There is at least a mismatch.

3) Since both TX and RX use the same field ->queue_mapping,
I assume normally it is supposed to be set and used only by one of them,
so the above commit kinda breaks this too.

Or am I still missing anything?

Thanks!

^ permalink raw reply

* Why do we use RX queue mapping for TX?
From: Cong Wang @ 2015-02-18 21:09 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev

Hi, David


With regarding to the following commit:

^ permalink raw reply

* Re: [PATCH v2 0/3] net: Linn Ethernet Packet Sniffer driver
From: Richard Cochran @ 2015-02-18 21:08 UTC (permalink / raw)
  To: Stathis Voukelatos
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
	abrestic-F7+t8E8rja9g9hUCZPvPmw
In-Reply-To: <cover.1424181053.git.stathis.voukelatos-zgcZaY4qg+21Qrn1Bg8BZw@public.gmane.org>

On Tue, Feb 17, 2015 at 02:03:30PM +0000, Stathis Voukelatos wrote:
> The command string for packet matching is stored in module RAM
> and consists of a sequence of 16-bit entries. Each entry includes
> an 8-bit command code and and 8-bit data value. Valid command
> codes are:
> 0 - Don't care
> 1 - Match: packet data must match command string byte
> 2 - Copy: packet data will be copied to FIFO
> 3 - Match/Stamp: if packet data matches string byte, a timestamp
>                  is copied into the FIFO
> 4 - Copy/Done: packet data will be copied into the FIFO.
>                This command terminates the command string.

Why do you need to expose this interface to user space at all?  Why
not just time stamp every frame?

How does the "Match" command work?  The frame must have one particular
byte?  That can't be right.  Please explain.

Thanks,
Richard
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] net/appletalk: LTPC needs virt_to_bus
From: Arnd Bergmann @ 2015-02-18 19:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, Arnaldo Carvalho de Melo, linux-kernel, linux-arm-kernel

The ltpc driver is rather outdated and does not get built on most
platforms because it requires the ISA_DMA_API symbol. However
there are some ARM platforms that have ISA_DMA_API but no virt_to_bus,
and they get this build error when enabling the ltpc driver.

drivers/net/appletalk/ltpc.c: In function 'handlefc':
drivers/net/appletalk/ltpc.c:380:2: error: implicit declaration of function 'virt_to_bus' [-Werror=implicit-function-declaration]
  set_dma_addr(dma,virt_to_bus(ltdmacbuf));
  ^

This adds another dependency in Kconfig to avoid that configuration.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index 4ce6ca5f3d36..dc6b78e5342f 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -40,7 +40,7 @@ config DEV_APPLETALK
 
 config LTPC
 	tristate "Apple/Farallon LocalTalk PC support"
-	depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API
+	depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS
 	help
 	  This allows you to use the AppleTalk PC card to connect to LocalTalk
 	  networks. The card is also known as the Farallon PhoneNet PC card.

^ permalink raw reply related

* [PATCH] net: smc91x: improve neponset hack
From: Arnd Bergmann @ 2015-02-18 19:47 UTC (permalink / raw)
  To: netdev
  Cc: davem, linux-arm-kernel, rmk+kernel, Dmitry Eremin-Solenikov,
	linux-kernel, Linus Walleij

The smc91x driver tries to support multiple platforms at compile
time, but they are mutually exclusive at runtime, and not clearly
defined.

Trying to build for CONFIG_SA1100_ASSABET without CONFIG_ASSABET_NEPONSET
results in this link error:

drivers/built-in.o: In function `smc_drv_probe':
:(.text+0x33310c): undefined reference to `neponset_ncr_frob'

since the neponset_ncr_set function is not defined otherwise.

Similarly, building for both CONFIG_SA1100_ASSABET and CONFIG_SA1100_PLEB
results in a different build error:

smsc/smc91x.c: In function 'smc_drv_probe':
smsc/smc91x.c:2299:2: error: implicit declaration of function 'neponset_ncr_set' [-Werror=implicit-function-declaration]
  neponset_ncr_set(NCR_ENET_OSC_EN);
  ^
smsc/smc91x.c:2299:19: error: 'NCR_ENET_OSC_EN' undeclared (first use in this function)
  neponset_ncr_set(NCR_ENET_OSC_EN);
                   ^

This is an attempt to fix the call site responsible for both
errors, making sure we call the function exactly when the driver
is actually trying to run on the assabet/neponset machine. With
this patch, I no longer see randconfig build errors in this file.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 88a55f95fe09..fa3f193b5f4d 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2355,7 +2355,7 @@ static int smc_drv_probe(struct platform_device *pdev)
 	ret = smc_request_attrib(pdev, ndev);
 	if (ret)
 		goto out_release_io;
-#if defined(CONFIG_SA1100_ASSABET)
+#if defined(CONFIG_ASSABET_NEPONSET) && !defined(CONFIG_SA1100_PLEB)
 	neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
 	platform_set_drvdata(pdev, ndev);

^ permalink raw reply related

* Re: [PATCH 1/1] tun: change speed from 10M to dynamically configured
From: Andy Gospodarek @ 2015-02-18 19:39 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: yzhu1, Francois Romieu, netdev, mst, jasowang, viro, davem,
	sergei.shtylyov, jonathon.reinhart
In-Reply-To: <20150216120345.4dfd9950@uryu.home.lan>

Proposed follow-up based on the errors in if_tunnel.h that were brought
to my attention with Stephen's patch.

(Dave, if you want a more official-looking post in a standalone thread I
can do that.)

From: Andy Gospodarek <gospo@cumulusnetworks.com>
Subject: [PATCH net-next] uapi: fixup whitespace for private ioctls

After Stephen's patch added support for new private ioctl (SIOCDRVINFO)
I noticed that his whitespace was correct, but the rest of the
whitespace for the other ioctls was wrong.  This fixes up the others and
should be applied after his.

CC: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Andy Gospodarek <gospo@cumulusnetworks.com>

---
 include/uapi/linux/if_tunnel.h | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 3430238..4a65a56 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -5,18 +5,18 @@
 #include <asm/byteorder.h>
 
 
-#define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
-#define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
-#define SIOCDELTUNNEL   (SIOCDEVPRIVATE + 2)
-#define SIOCCHGTUNNEL   (SIOCDEVPRIVATE + 3)
-#define SIOCGETPRL      (SIOCDEVPRIVATE + 4)
-#define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
-#define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
-#define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
-#define SIOCGET6RD      (SIOCDEVPRIVATE + 8)
-#define SIOCADD6RD      (SIOCDEVPRIVATE + 9)
-#define SIOCDEL6RD      (SIOCDEVPRIVATE + 10)
-#define SIOCCHG6RD      (SIOCDEVPRIVATE + 11)
+#define SIOCGETTUNNEL	(SIOCDEVPRIVATE + 0)
+#define SIOCADDTUNNEL	(SIOCDEVPRIVATE + 1)
+#define SIOCDELTUNNEL	(SIOCDEVPRIVATE + 2)
+#define SIOCCHGTUNNEL	(SIOCDEVPRIVATE + 3)
+#define SIOCGETPRL	(SIOCDEVPRIVATE + 4)
+#define SIOCADDPRL	(SIOCDEVPRIVATE + 5)
+#define SIOCDELPRL	(SIOCDEVPRIVATE + 6)
+#define SIOCCHGPRL	(SIOCDEVPRIVATE + 7)
+#define SIOCGET6RD	(SIOCDEVPRIVATE + 8)
+#define SIOCADD6RD	(SIOCDEVPRIVATE + 9)
+#define SIOCDEL6RD	(SIOCDEVPRIVATE + 10)
+#define SIOCCHG6RD	(SIOCDEVPRIVATE + 11)
 #define SIOCDRVINFO	(SIOCDEVPRIVATE + 12)
 
 struct ip_tunnel_info {
-- 
1.9.3

^ permalink raw reply related

* Re: [PATCH 1/1] tun: change speed from 10M to dynamically configured
From: Andy Gospodarek @ 2015-02-18 19:29 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: yzhu1, Francois Romieu, netdev, mst, jasowang, viro, davem,
	sergei.shtylyov, jonathon.reinhart
In-Reply-To: <20150216120345.4dfd9950@uryu.home.lan>

On Mon, Feb 16, 2015 at 12:03:45PM -0500, Stephen Hemminger wrote:
> I would like to propose this is as a more complete alternative.
> 
> From: Stephen Hemminger <stephen@networkpluber.org>
> Subject: [PATCH] tun: support overriding ethtool information
> 
> Extensions to allow masqurade of ethtool info and device statistics.
> This is useful to provide correct information to SNMP and OSPF routing
> daemons when doing hw/sw offload of network device.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> 
> ---
>  drivers/net/tun.c              | 139 +++++++++++++++++++++++++++++++++++++----
>  include/uapi/linux/if_tunnel.h |   9 +++
>  2 files changed, 135 insertions(+), 13 deletions(-)
> 
> --- a/drivers/net/tun.c	2015-02-16 11:58:00.651506008 -0500
> +++ b/drivers/net/tun.c	2015-02-16 11:59:15.560842558 -0500
> @@ -60,6 +60,7 @@
>  #include <linux/if_arp.h>
>  #include <linux/if_ether.h>
>  #include <linux/if_tun.h>
> +#include <linux/if_tunnel.h>
>  #include <linux/if_vlan.h>
>  #include <linux/crc32.h>
>  #include <linux/nsproxy.h>
> @@ -204,6 +205,9 @@ struct tun_struct {
>  	struct list_head disabled;
>  	void *security;
>  	u32 flow_count;
> +	u8 duplex;
> +	u32 speed;
> +	struct ip_tunnel_info	info;
>  };
>  
>  static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
> @@ -866,6 +870,33 @@ static netdev_features_t tun_net_fix_fea
>  
>  	return (features & tun->set_features) | (features & ~TUN_USER_FEATURES);
>  }
> +
> +static int
> +tun_net_set_info(struct net_device *dev, const void __user *data)
> +{
> +	struct tun_struct *tun = netdev_priv(dev);
> +	struct ip_tunnel_info info;
> +
> +	if (!capable(CAP_NET_ADMIN))
> +		return -EPERM;
> +
> +	if (copy_from_user(&info, data, sizeof(info)))
> +		return -EFAULT;
> +
> +	strlcpy(tun->info.driver, info.driver, sizeof(tun->info.driver));
> +	strlcpy(tun->info.bus, info.bus, sizeof(tun->info.bus));
> +	return 0;
> +}
> +
> +static int
> +tun_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> +{
> +	if (cmd != SIOCDRVINFO)
> +		return -EOPNOTSUPP;
> +
> +	return tun_net_set_info(dev, ifr->ifr_ifru.ifru_data);
> +}
> +
>  #ifdef CONFIG_NET_POLL_CONTROLLER
>  static void tun_poll_controller(struct net_device *dev)
>  {
> @@ -904,6 +935,7 @@ static const struct net_device_ops tap_n
>  	.ndo_change_mtu		= tun_net_change_mtu,
>  	.ndo_fix_features	= tun_net_fix_features,
>  	.ndo_set_rx_mode	= tun_net_mclist,
> +	.ndo_do_ioctl		= tun_net_ioctl,
>  	.ndo_set_mac_address	= eth_mac_addr,
>  	.ndo_validate_addr	= eth_validate_addr,
>  	.ndo_select_queue	= tun_select_queue,
> @@ -1408,6 +1440,8 @@ static void tun_setup(struct net_device
>  
>  	tun->owner = INVALID_UID;
>  	tun->group = INVALID_GID;
> +	tun->speed = SPEED_10;
> +	tun->duplex = DUPLEX_FULL;
>  
>  	dev->ethtool_ops = &tun_ethtool_ops;
>  	dev->destructor = tun_free_netdev;
> @@ -1654,6 +1688,11 @@ static int tun_set_iff(struct net *net,
>  
>  		spin_lock_init(&tun->lock);
>  
> +		strlcpy(tun->info.driver, DRV_NAME, sizeof(tun->info.driver));
> +		strlcpy(tun->info.bus,
> +			(ifr->ifr_flags & IFF_TUN) ? "tun" : "tap",
> +			sizeof(tun->info.bus));
> +
>  		err = security_tun_dev_alloc_security(&tun->security);
>  		if (err < 0)
>  			goto err_free_dev;
> @@ -2253,10 +2292,12 @@ static struct miscdevice tun_miscdev = {
>  
>  static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
>  {
> +	struct tun_struct *tun = netdev_priv(dev);
> +
>  	cmd->supported		= 0;
>  	cmd->advertising	= 0;
> -	ethtool_cmd_speed_set(cmd, SPEED_10);
> -	cmd->duplex		= DUPLEX_FULL;
> +	ethtool_cmd_speed_set(cmd, tun->speed);
> +	cmd->duplex		= tun->duplex;
>  	cmd->port		= PORT_TP;
>  	cmd->phy_address	= 0;
>  	cmd->transceiver	= XCVR_INTERNAL;
> @@ -2266,21 +2307,24 @@ static int tun_get_settings(struct net_d
>  	return 0;
>  }
>  
> +static int tun_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
> +{
> +	struct tun_struct *tun = netdev_priv(dev);
> +
> +	tun->speed = ethtool_cmd_speed(ecmd);
> +	tun->duplex = ecmd->duplex;
> +
> +	return 0;
> +}
> +
>  static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
>  {
>  	struct tun_struct *tun = netdev_priv(dev);
>  
> -	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
> +	strlcpy(info->driver, tun->info.driver, sizeof(info->driver));
>  	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
>  
> -	switch (tun->flags & TUN_TYPE_MASK) {
> -	case IFF_TUN:
> -		strlcpy(info->bus_info, "tun", sizeof(info->bus_info));
> -		break;
> -	case IFF_TAP:
> -		strlcpy(info->bus_info, "tap", sizeof(info->bus_info));
> -		break;
> -	}
> +	strlcpy(info->bus_info, tun->info.bus, sizeof(info->bus_info));
>  }
>  
>  static u32 tun_get_msglevel(struct net_device *dev)
> @@ -2303,6 +2347,7 @@ static void tun_set_msglevel(struct net_
>  
>  static const struct ethtool_ops tun_ethtool_ops = {
>  	.get_settings	= tun_get_settings,
> +	.set_settings	= tun_set_settings,
>  	.get_drvinfo	= tun_get_drvinfo,
>  	.get_msglevel	= tun_get_msglevel,
>  	.set_msglevel	= tun_set_msglevel,
> --- a/include/uapi/linux/if_tunnel.h	2015-02-16 11:58:00.651506008 -0500
> +++ b/include/uapi/linux/if_tunnel.h	2015-02-16 11:58:00.651506008 -0500
> @@ -17,6 +17,12 @@
>  #define SIOCADD6RD      (SIOCDEVPRIVATE + 9)
>  #define SIOCDEL6RD      (SIOCDEVPRIVATE + 10)
>  #define SIOCCHG6RD      (SIOCDEVPRIVATE + 11)
> +#define SIOCDRVINFO	(SIOCDEVPRIVATE + 12)
My only complaint, is that the whitespace is different from the line
above.  Rather than requesting you fix this, I'll post a follow-up that
fixes all of these.

Acked-by: Andy Gospodarek <gospo@cumulusnetworks.com>

> +
> +struct ip_tunnel_info {
> +	char driver[32];
> +	char bus[32];
> +};
>  
>  #define GRE_CSUM	__cpu_to_be16(0x8000)
>  #define GRE_ROUTING	__cpu_to_be16(0x4000)
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH/RFC 3/3] net: unft: Add Userspace hairpin network flow table device
From: Simon Horman @ 2015-02-18 19:25 UTC (permalink / raw)
  To: netdev; +Cc: Simon Horman
In-Reply-To: <1424287559-25700-1-git-send-email-simon.horman@netronome.com>

*** Not for Upstream Merge
*** For informational purposes only

Allows the implementation of the NDO's proposed by John Fastabend's API
to be implemented in user-space. This is done using netlink messages.

Limitations:
* Both the design and the implementation are slow

I have also written user-space code. There are two portions:

1. flow-table

   This may be used to send and receive messages from the Flow API.
   It a command-line utility which may be used to exercise the flow API.
   And a library to help achieve this. An interesting portion
   of the library is a small framework for converting between
   netlink and JSON.

   It is available here: https://github.com/horms/flow-table
   The licence is GPLv2

   It overlaps to some extent with user-space code by John Fastabend.
   I was not aware of that work which he was doing concurrently.

2. flow-table-hairpin

   This is a daemon that listens for messages hairpined back
   to user-space and responds accordingly. That is, the user-space
   backing of the NDOs of the Flow API.

   It includes a simple flow table backend (ftbe) abstraction
   and a dummy implementation that stores flows in a local list
   ** and does nothing else with them ***

   It is available here: https://github.com/horms/flow-table-hairpin
   The licence is GPLv2

Simple usage example:

ip link add type unft

flow-table-hairpind \
        --tables tables.json \
        --headers headers.json \
        --actions actions.json \
        --header-graph header-graph.json \
        --table-graph table-graph.json &

flow-table-ctl get-tables unft0

Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
 drivers/net/Kconfig  |    9 +
 drivers/net/Makefile |    1 +
 drivers/net/unft.c   | 1520 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1530 insertions(+)
 create mode 100644 drivers/net/unft.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d6607ee..9a4ddb1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -268,6 +268,15 @@ config NLMON
 	  diagnostics, etc. This is mostly intended for developers or support
 	  to debug netlink issues. If unsure, say N.
 
+config UNFT
+	tristate "User-Space hairpin network flow table device"
+	depends on NET_FLOW_TABLES
+	---help---
+	  This option enables a hairpin network flow table device. The
+	  purpose of this is to reflect network flow table API calls,
+	  made via netlink messages, to user-space to allow prototyping
+	  of implementations there. If unsure, say N.
+
 endif # NET_CORE
 
 config SUNGEM_PHY
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e25fdd7..88ca294 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_VXLAN) += vxlan.o
 obj-$(CONFIG_NLMON) += nlmon.o
+obj-$(CONFIG_UNFT) += unft.o
 
 #
 # Networking Drivers
diff --git a/drivers/net/unft.c b/drivers/net/unft.c
new file mode 100644
index 0000000..483dc8d
--- /dev/null
+++ b/drivers/net/unft.c
@@ -0,0 +1,1520 @@
+/* Based on nlmon.c by Daniel Borkmann, Mathieu Geli et al. */
+/* Based on flow_table.c by John Fastabend */
+/*
+ * include/uapi/linux/if_flow_hairpin.h -
+ * Hairpin to allow the messages of the Flow table interface for
+ * Swtich devices to be forwarded to user-space
+ * Copyright (c) 2014 Simon Horman <simon.horman@netronome.com>
+ *
+ * Based on: flow_table.c
+ * Copyright (c) 2014 John Fastabend <john.r.fastabend@intel.com>
+ *
+ * Based on nlmon.c by Daniel Borkmann, Mathieu Geli et al.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Author: Simon Horman <simon.horman@netronome.com>
+ */
+
+#include <linux/if_arp.h>
+#include <linux/if_flow_common.h>
+#include <linux/if_flow_hairpin.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <net/genetlink.h>
+#include <net/sock.h>
+#include <net/rtnetlink.h>
+
+static struct genl_family net_flow_hairpin_nl_family = {
+	.id = GENL_ID_GENERATE,
+	.name = NFLH_GENL_NAME,
+	.version = NFLH_GENL_VERSION,
+	.maxattr = NFLH_MAX,
+	.netnsok = true,
+};
+
+/* Protected by genl_lock */
+static u32 net_flow_hairpin_listener_pid;
+static bool net_flow_hairpin_listener_set;
+static struct net_flow_tbl **unft_table_list;
+static struct net_flow_hdr **unft_header_list;
+static struct net_flow_action **unft_action_list;
+static struct net_flow_hdr_node **unft_header_nodes;
+static struct net_flow_tbl_node **unft_table_nodes;
+
+#ifdef CONFIG_NET_NS
+/* Protected by genl_lock */
+static struct net *net_flow_hairpin_listener_net;
+#endif
+
+/* In flight encap request details.
+ * Protected by genl_lock.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(unft_msg_wq);
+static int unft_msg_state;
+static int unft_msg_status;
+
+enum {
+	UNFT_MSG_S_NONE,
+	UNFT_MSG_S_REQUEST,
+	UNFT_MSG_S_REPLY,
+};
+
+/* This is 64-bits to allow plenty of space
+ * for example to partition the sequence number space on a per-CPU basis.
+ */
+static u64 unft_msg_seq;
+
+static int unft_flow_encap_request(struct net_device *dev, u32 cmd,
+				   int (*cb)(struct sk_buff *msg, void *priv),
+				   void *priv)
+{
+	int err = -ENOBUFS;
+	struct genl_info info = {
+		.dst_sk = read_pnet(&net_flow_hairpin_listener_net)->genl_sock,
+		.snd_portid = net_flow_hairpin_listener_pid,
+	};
+	struct genlmsghdr *hdr;
+	struct nlattr *encap, *encap_attr;
+	struct sk_buff *msg;
+
+	/* At this time only one message is allowed at a time */
+	if (unft_msg_state != UNFT_MSG_S_NONE)
+		return -EBUSY;
+
+	msg = genlmsg_new_unicast(NLMSG_DEFAULT_SIZE, &info, GFP_KERNEL);
+	if (!msg)
+		return -ENOBUFS;
+
+	hdr = genlmsg_put(msg, 0, 0, &net_flow_hairpin_nl_family, 0,
+			  NFLH_CMD_ENCAP);
+	if (!hdr)
+		goto err_msg;
+
+	encap = nla_nest_start(msg, NFLH_ENCAP);
+	if (!encap) {
+		err = -EMSGSIZE;
+		goto err_msg;
+	}
+
+	unft_msg_state = UNFT_MSG_S_REQUEST;
+	unft_msg_seq++;
+
+	if (nla_put_u32(msg, NFLH_ENCAP_CMD_TYPE,
+			NFLH_ENCAP_CMD_NFL_CMD) ||
+	    nla_put_u32(msg, NFLH_ENCAP_CMD, cmd) ||
+	    nla_put_u64(msg, NFLH_ENCAP_SEQ, unft_msg_seq)) {
+		err = -ENOBUFS;
+		goto err_encap;
+	}
+
+	encap_attr = nla_nest_start(msg, NFLH_ENCAP_ATTR);
+	if (!encap) {
+		err = -EMSGSIZE;
+		goto err_encap;
+	}
+
+	if (nla_put_u32(msg, NFL_IDENTIFIER_TYPE,
+			NFL_IDENTIFIER_IFINDEX) ||
+	    nla_put_u32(msg, NFL_IDENTIFIER, dev->ifindex)) {
+		err = -ENOBUFS;
+		goto err_encap_attr;
+	}
+
+	if (cb) {
+		err = cb(msg, priv);
+		if (err)
+			goto err_encap_attr;
+	}
+
+	nla_nest_end(msg, encap_attr);
+	nla_nest_end(msg, encap);
+
+	err = genlmsg_end(msg, hdr);
+	if (err < 0)
+		goto err_msg;
+
+	err = genlmsg_unicast(read_pnet(&net_flow_hairpin_listener_net),
+			      msg, net_flow_hairpin_listener_pid);
+	if (err)
+		return err;
+
+	genl_unlock();
+	err = wait_event_interruptible_timeout(unft_msg_wq,
+					       unft_msg_state == UNFT_MSG_S_REPLY,
+					       msecs_to_jiffies(5000));
+	genl_lock();
+	if (err < 0)
+		goto out;
+	if (unft_msg_state != UNFT_MSG_S_REPLY) {
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	err = unft_msg_status;
+	goto out;
+
+err_encap_attr:
+	nla_nest_cancel(msg, encap_attr);
+err_encap:
+	nla_nest_cancel(msg, encap);
+err_msg:
+	nlmsg_free(msg);
+out:
+	unft_msg_state = UNFT_MSG_S_NONE;
+
+	return err;
+}
+
+static int unft_set_del_rule_cb(struct sk_buff *msg, void *priv)
+{
+	int err;
+	struct net_flow_rule *rule = priv;
+	struct nlattr *start;
+
+	start = nla_nest_start(msg, NFL_FLOWS);
+	if (!start)
+		return -EMSGSIZE;
+
+	err = net_flow_put_rule(msg, rule);
+	if (err) {
+		nla_nest_cancel(msg, start);
+		return -ENOBUFS;
+	}
+
+	nla_nest_end(msg, start);
+
+	return 0;
+}
+
+static int unft_flow_table_set_rule(struct net_device *dev,
+				    struct net_flow_rule *rule)
+{
+	return unft_flow_encap_request(dev, NFL_TABLE_CMD_SET_FLOWS,
+				       unft_set_del_rule_cb, rule);
+}
+
+static int unft_flow_table_del_rule(struct net_device *dev,
+				     struct net_flow_rule *rule)
+{
+	return unft_flow_encap_request(dev, NFL_TABLE_CMD_DEL_FLOWS,
+				       unft_set_del_rule_cb, rule);
+}
+
+static const
+struct nla_policy net_flow_hairpin_listener_policy[NFLH_LISTENER_ATTR_MAX + 1] = {
+	[NFLH_LISTENER_ATTR_TYPE] = { .type = NLA_U32,},
+	[NFLH_LISTENER_ATTR_PIDS] = { .type = NLA_U32,},
+};
+
+static int net_flow_table_hairpin_cmd_set_listener(struct sk_buff *skb,
+						   struct genl_info *info)
+{
+	int err;
+	struct nlattr *tb[NFLH_LISTENER_ATTR_MAX + 1];
+	u32 pid, type;
+
+	if (!info->attrs[NFLH_LISTENER])
+		return -EINVAL;
+
+	err = nla_parse_nested(tb, NFLH_LISTENER_ATTR_MAX,
+			       info->attrs[NFLH_LISTENER],
+			       net_flow_hairpin_listener_policy);
+	if (err)
+		return err;
+
+	if (!tb[NFLH_LISTENER_ATTR_TYPE] ||
+	    !tb[NFLH_LISTENER_ATTR_PIDS])
+		return -EINVAL;
+	type = nla_get_u32(tb[NFLH_LISTENER_ATTR_TYPE]);
+	if (type != NFLH_LISTENER_ATTR_TYPE_ENCAP)
+		return -EOPNOTSUPP;
+
+	if (tb[NFLH_LISTENER_ATTR_PIDS]) {
+		/* Only the first pid is used at this time */
+		pid = nla_get_u32(tb[NFLH_LISTENER_ATTR_PIDS]);
+		net_flow_hairpin_listener_pid = pid;
+		write_pnet(&net_flow_hairpin_listener_net,
+			   hold_net(sock_net(skb->sk)));
+		net_flow_hairpin_listener_set = true;
+	} else {
+		net_flow_hairpin_listener_set = false;
+	}
+
+	return 0;
+}
+
+static int net_flow_table_hairpin_cmd_get_listener(struct sk_buff *skb,
+						   struct genl_info *info)
+{
+	int err;
+	struct genlmsghdr *hdr;
+	struct nlattr *start;
+	struct nlattr *tb[NFLH_LISTENER_ATTR_MAX + 1];
+	struct sk_buff *msg = NULL;
+	u32 type;
+
+	if (!info->attrs[NFLH_LISTENER]) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	err = nla_parse_nested(tb, NFLH_LISTENER_ATTR_MAX,
+			       info->attrs[NFLH_LISTENER],
+			       net_flow_hairpin_listener_policy);
+	if (err)
+		goto err;
+
+	if (!tb[NFLH_LISTENER_ATTR_TYPE]) {
+		err = -EINVAL;
+		goto err;
+	}
+	type = nla_get_u32(tb[NFLH_LISTENER_ATTR_TYPE]);
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOBUFS;
+		goto err;
+	}
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+			  &net_flow_hairpin_nl_family, 0,
+			  NFLH_CMD_GET_LISTENER);
+	if (!hdr) {
+		err = -ENOBUFS;
+		goto err;
+	}
+
+	start = nla_nest_start(msg, NFLH_LISTENER);
+	if (!start)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(msg, NFLH_LISTENER_ATTR_TYPE,
+			NFLH_LISTENER_ATTR_TYPE_ENCAP))
+		return -ENOBUFS;
+
+	if (net_flow_hairpin_listener_set &&
+	    nla_put_u32(msg, NFLH_LISTENER_ATTR_PIDS,
+			net_flow_hairpin_listener_pid))
+		return -ENOBUFS;
+
+	nla_nest_end(msg, start);
+
+	err = genlmsg_end(msg, hdr);
+	if (err < 0)
+		goto err;
+
+	return genlmsg_reply(msg, info);
+
+err:
+	nlmsg_free(msg);
+	return err;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static struct net_flow_field_ref *
+unft_encap_get_field_refs(struct nlattr *attr)
+{
+	int count, err, rem;
+	struct net_flow_field_ref *refs;
+	struct nlattr *a;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_FIELD_REF)
+			count++;
+
+	refs = kcalloc(count + 1, sizeof *refs, GFP_KERNEL);
+	if (!refs)
+		return ERR_PTR(-ENOMEM);
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		if (nla_type(a) != NFL_FIELD_REF)
+			continue;
+		err = net_flow_get_field(&refs[count++], a);
+		if (err) {
+			kfree(refs);
+			return ERR_PTR(err);
+		}
+	}
+
+	return refs;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int *
+unft_encap_get_action_descs(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+	int *actions;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_ACTION_ATTR_UID)
+			count++;
+
+	actions = kcalloc(count + 1, sizeof *actions, GFP_KERNEL);
+	if (!actions)
+		return ERR_PTR(-ENOMEM);
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		u32 x;
+
+		if (nla_type(a) != NFL_ACTION_ATTR_UID)
+			continue;
+		x = nla_get_u32(a);
+		if (!x || x > INT_MAX) {
+			kfree(actions);
+			return ERR_PTR(-EINVAL);
+		}
+		actions[count] = x;
+	}
+
+	return actions;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static char *unft_encap_get_name(struct nlattr *attr)
+{
+	int max;
+	char *name;
+
+	max = nla_len(attr);
+	if (max > NFL_MAX_NAME)
+		max = NFL_MAX_NAME;
+	name = kzalloc(max, GFP_KERNEL);
+	if (!name)
+		return NULL;
+	nla_strlcpy(name, attr, max);
+
+	return name;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static const
+struct nla_policy flow_table_table_attr_policy[NFL_TABLE_ATTR_MAX + 1] =
+{
+	[NFL_TABLE_ATTR_NAME]		= { .type = NLA_STRING },
+	[NFL_TABLE_ATTR_UID]		= { .type = NLA_U32 },
+	[NFL_TABLE_ATTR_SOURCE]		= { .type = NLA_U32 },
+	[NFL_TABLE_ATTR_APPLY]		= { .type = NLA_U32 },
+	[NFL_TABLE_ATTR_SIZE]		= { .type = NLA_U32 },
+	[NFL_TABLE_ATTR_MATCHES]	= { .type = NLA_NESTED },
+	[NFL_TABLE_ATTR_ACTIONS]	= { .type = NLA_NESTED },
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_table(struct net_flow_tbl *table)
+{
+	kfree(table->name);
+	kfree(table->matches);
+	kfree(table->actions);
+	kfree(table);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+struct net_flow_tbl *unft_encap_get_table(struct nlattr *attr)
+{
+	int err = -EINVAL;
+	struct net_flow_tbl *table;
+	struct nlattr *attrs[NFL_TABLE_ATTR_MAX + 1];
+
+	table = kzalloc(sizeof *table, GFP_KERNEL);
+	if (!table)
+		return ERR_PTR(-ENOMEM);
+
+	err = nla_parse_nested(attrs, NFL_TABLE_ATTR_MAX,
+			       attr, flow_table_table_attr_policy);
+	if (err)
+		goto err;
+
+	if (!attrs[NFL_TABLE_ATTR_NAME] || !attrs[NFL_TABLE_ATTR_UID] ||
+	    !attrs[NFL_TABLE_ATTR_SOURCE] || !attrs[NFL_TABLE_ATTR_APPLY] ||
+	    !attrs[NFL_TABLE_ATTR_SIZE] || !attrs[NFL_TABLE_ATTR_UID] ||
+	    !attrs[NFL_TABLE_ATTR_MATCHES] || !attrs[NFL_TABLE_ATTR_ACTIONS])
+		goto err;
+
+	table->name = unft_encap_get_name(attrs[NFL_TABLE_ATTR_NAME]);
+	if (!table->name) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	table->uid = nla_get_u32(attrs[NFL_TABLE_ATTR_UID]);
+	table->source = nla_get_u32(attrs[NFL_TABLE_ATTR_SOURCE]);
+	table->apply_action = nla_get_u32(attrs[NFL_TABLE_ATTR_APPLY]);
+	table->size = nla_get_u32(attrs[NFL_TABLE_ATTR_SIZE]);
+
+	table->matches = unft_encap_get_field_refs(attrs[NFL_TABLE_ATTR_MATCHES]);
+	if (IS_ERR(table->matches)) {
+		err = PTR_ERR(table->matches);
+		goto err;
+	}
+
+	table->actions = unft_encap_get_action_descs(attrs[NFL_TABLE_ATTR_ACTIONS]);
+	if (IS_ERR(table->actions)) {
+		err = PTR_ERR(table->actions);
+		goto err;
+	}
+
+	return table;
+err:
+	unft_encap_free_table(table);
+	return ERR_PTR(err);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_tables(struct net_flow_tbl **tables)
+{
+	int i;
+
+	if (!tables)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(tables[i]); i++)
+		unft_encap_free_table(tables[i]);
+
+	kfree(tables);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_tables(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+
+	if (!attr || unft_table_list)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_TABLE)
+			count++;
+
+	unft_table_list = kcalloc(count + 1, sizeof *unft_table_list,
+				  GFP_KERNEL);
+	if (!unft_table_list)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		if (nla_type(a) != NFL_TABLE)
+			continue;
+
+		unft_table_list[count] = unft_encap_get_table(a);
+		if (IS_ERR(unft_table_list[count])) {
+			int err = PTR_ERR(unft_table_list[count]);
+
+			unft_encap_free_tables(unft_table_list);
+			unft_table_list = NULL;
+			return err;
+		}
+
+		count++;
+	}
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static const
+struct nla_policy flow_table_field_attr_policy[NFL_FIELD_ATTR_MAX + 1] =
+{
+	[NFL_FIELD_ATTR_NAME]		= { .type = NLA_STRING },
+	[NFL_FIELD_ATTR_UID]		= { .type = NLA_U32 },
+	[NFL_FIELD_ATTR_BITWIDTH]	= { .type = NLA_U32 },
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+int unft_encap_get_field(struct nlattr *attr, struct net_flow_field *field)
+{
+	int err;
+	struct nlattr *attrs[NFL_FIELD_ATTR_MAX + 1];
+
+	err = nla_parse_nested(attrs, NFL_FIELD_ATTR_MAX, attr,
+			       flow_table_field_attr_policy);
+	if (err)
+		return err;
+
+	if (!attrs[NFL_FIELD_ATTR_NAME] || !attrs[NFL_FIELD_ATTR_UID] ||
+	    !attrs[NFL_FIELD_ATTR_BITWIDTH])
+		return -EINVAL;
+
+	field->name = unft_encap_get_name(attrs[NFL_FIELD_ATTR_NAME]);
+	if (!field->name)
+		return -ENOMEM;
+
+	field->uid = nla_get_u32(attrs[NFL_FIELD_ATTR_UID]);
+	field->bitwidth = nla_get_u32(attrs[NFL_FIELD_ATTR_BITWIDTH]);
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_fields(struct net_flow_field *fields, int count)
+{
+	int i;
+
+	if (!fields)
+		return;
+
+	for (i = 0; i < count; i++)
+		kfree(fields[i].name);
+
+	kfree(fields);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_header_fields(struct nlattr *attr,
+					struct net_flow_hdr *header)
+{
+	int count, rem;
+	struct nlattr *a;
+
+	if (!attr)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_FIELD)
+			count++;
+
+	header->field_sz = count;
+	header->fields = kcalloc(count, sizeof *header->fields, GFP_KERNEL);
+	if (!header->fields)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		int err;
+
+		if (nla_type(a) != NFL_FIELD)
+			continue;
+
+		err = unft_encap_get_field(a, &header->fields[count]);
+		if (err) {
+			unft_encap_free_fields(header->fields, count);
+			return err;
+		}
+
+		count++;
+	}
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_header(struct net_flow_hdr *header)
+{
+	unft_encap_free_fields(header->fields, header->field_sz);
+	kfree(header->name);
+	kfree(header);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static const
+struct nla_policy flow_table_header_attr_policy[NFL_HEADER_ATTR_MAX + 1] =
+{
+	[NFL_HEADER_ATTR_NAME]		= { .type = NLA_STRING },
+	[NFL_HEADER_ATTR_UID]		= { .type = NLA_U32 },
+	[NFL_HEADER_ATTR_FIELDS]	= { .type = NLA_NESTED },
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+struct net_flow_hdr *unft_encap_get_header(struct nlattr *attr)
+{
+	int err = -EINVAL;
+	struct net_flow_hdr *header;
+	struct nlattr *attrs[NFL_HEADER_ATTR_MAX + 1];
+
+	header = kzalloc(sizeof *header, GFP_KERNEL);
+	if (!header)
+		return ERR_PTR(-ENOMEM);
+
+	err = nla_parse_nested(attrs, NFL_HEADER_ATTR_MAX, attr,
+			       flow_table_header_attr_policy);
+	if (err)
+		goto err;
+
+	if (!attrs[NFL_HEADER_ATTR_NAME] || !attrs[NFL_HEADER_ATTR_UID] ||
+	    !attrs[NFL_HEADER_ATTR_FIELDS])
+		goto err;
+
+	header->name = unft_encap_get_name(attrs[NFL_HEADER_ATTR_NAME]);
+	if (!header->name) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	header->uid = nla_get_u32(attrs[NFL_HEADER_ATTR_UID]);
+
+	err = unft_encap_get_header_fields(attrs[NFL_HEADER_ATTR_FIELDS],
+					   header);
+	if (err)
+		goto err;
+
+	return header;
+err:
+	unft_encap_free_header(header);
+	return ERR_PTR(err);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_headers(struct net_flow_hdr **headers)
+{
+	int i;
+
+	if (!headers)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(headers[i]); i++)
+		unft_encap_free_header(headers[i]);
+
+	kfree(headers);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_headers(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+
+	if (!attr || unft_header_list)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_HEADER)
+			count++;
+
+	unft_header_list = kcalloc(count + 1, sizeof *unft_header_list,
+				  GFP_KERNEL);
+	if (!unft_header_list)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		if (nla_type(a) != NFL_HEADER)
+			continue;
+
+		unft_header_list[count] = unft_encap_get_header(a);
+		if (IS_ERR(unft_header_list[count])) {
+			int err = PTR_ERR(unft_header_list[count]);
+
+			unft_encap_free_headers(unft_header_list);
+			unft_header_list = NULL;
+			return err;
+		}
+
+		count++;
+	}
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_actions(struct net_flow_action **actions)
+{
+	int i;
+
+	if (!actions)
+		return;
+
+	for (i = 0; actions[i]; i++) {
+		if (actions[i]->args) {
+			kfree(actions[i]->args->name);
+			kfree(actions[i]->args);
+		}
+		kfree(actions[i]);
+	}
+
+	kfree(actions);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_actions(struct nlattr *attr)
+{
+	int count, rem;
+	int err = 0;
+	struct nlattr *a;
+
+	if (!attr || unft_action_list)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_HEADER)
+			count++;
+
+	unft_action_list = kcalloc(count + 1, sizeof *unft_action_list,
+				  GFP_KERNEL);
+	if (!unft_action_list)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		int err;
+
+		if (nla_type(a) != NFL_HEADER)
+			continue;
+
+		unft_action_list[count] = kzalloc(sizeof *unft_action_list[count],
+						  GFP_KERNEL);
+		if (!unft_action_list[count]) {
+			err = -ENOMEM;
+			goto err;
+		}
+
+		err = net_flow_get_action(unft_action_list[count], a);
+		if (err)
+			goto err;
+
+		count++;
+	}
+
+	return 0;
+
+err:
+	unft_encap_free_actions(unft_action_list);
+	unft_action_list = NULL;
+	return err;
+}
+
+/* Copied from flow_table.c */
+static const
+struct nla_policy net_flow_field_policy[NFL_FIELD_REF_MAX + 1] = {
+        [NFL_FIELD_REF_NEXT_NODE] = { .type = NLA_U32,},
+        [NFL_FIELD_REF_INSTANCE]  = { .type = NLA_U32,},
+        [NFL_FIELD_REF_HEADER]    = { .type = NLA_U32,},
+        [NFL_FIELD_REF_FIELD]     = { .type = NLA_U32,},
+        [NFL_FIELD_REF_MASK_TYPE] = { .type = NLA_U32,},
+        [NFL_FIELD_REF_TYPE]      = { .type = NLA_U32,},
+        [NFL_FIELD_REF_VALUE]     = { .type = NLA_BINARY,
+                                      .len = sizeof(u64)},
+        [NFL_FIELD_REF_MASK]      = { .type = NLA_BINARY,
+                                      .len = sizeof(u64)},
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+int unft_encap_get_jump_table(struct net_flow_jump_table *table,
+			      struct nlattr *attr)
+{
+	int err;
+	struct nlattr *attrs[NFL_FIELD_REF_MAX + 1];
+
+	err = net_flow_get_field(&table->field, attr);
+	if (err)
+		return err;
+
+	/* net_flow_get_field() does not parse NFL_FIELD_REF_NEXT_NODE
+	 * which has no corresponding field in struct net_flow_field_ref
+	 */
+
+	err = nla_parse_nested(attrs, NFL_FIELD_REF_MAX,
+			       attr, net_flow_field_policy);
+	if (err)
+		return err;
+
+	if (!attrs[NFL_FIELD_REF_NEXT_NODE])
+		return -EINVAL;
+
+	table->node =  nla_get_u32(attrs[NFL_FIELD_REF_NEXT_NODE]);
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static struct net_flow_jump_table *unft_encap_get_jump_tables(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+	struct net_flow_jump_table *tables;
+
+	count = 0;
+	if (attr)
+		nla_for_each_nested(a, attr, rem)
+			if (nla_type(a) == NFL_HEADER_NODE_HDRS_VALUE)
+				count++;
+
+	tables = kcalloc(count + 1, sizeof *tables, GFP_KERNEL);
+	if (!tables)
+		return ERR_PTR(-ENOMEM);
+
+	if (!attr)
+		return tables;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		int err;
+
+		if (nla_type(a) != NFL_HEADER_NODE_HDRS_VALUE)
+			continue;
+
+		err = unft_encap_get_jump_table(&tables[count], a);
+		if (err) {
+			kfree(tables);
+			return ERR_PTR(err);
+		}
+
+		count++;
+	}
+
+	return tables;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int *unft_encap_get_header_node_hdrs(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+	int *hdrs;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_HEADER_NODE_HDRS_VALUE)
+			count++;
+
+	hdrs = kcalloc(count + 1, sizeof *hdrs, GFP_KERNEL);
+	if (!hdrs)
+		return ERR_PTR(-ENOMEM);
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		u32 value;
+
+		if (nla_type(a) != NFL_HEADER_NODE_HDRS_VALUE)
+			continue;
+
+		value = nla_get_u32(a);
+		if (value > INT_MAX)
+			return ERR_PTR(-EINVAL);
+		hdrs[count++] = value;
+	}
+
+	return hdrs;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_header_node(struct net_flow_hdr_node *node)
+{
+	kfree(node->name);
+	kfree(node->hdrs);
+	kfree(node->jump);
+	kfree(node);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static const
+struct nla_policy flow_table_header_node_policy[NFL_HEADER_NODE_MAX + 1] =
+{
+        [NFL_HEADER_NODE_NAME]          = { .type = NLA_STRING },
+        [NFL_HEADER_NODE_UID]           = { .type = NLA_U32 },
+        [NFL_HEADER_NODE_HDRS]          = { .type = NLA_NESTED },
+        [NFL_HEADER_NODE_JUMP]          = { .type = NLA_NESTED },
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+struct net_flow_hdr_node *unft_encap_get_header_node(struct nlattr *attr)
+{
+	int err;
+	struct net_flow_hdr_node *node;
+	struct nlattr *attrs[NFL_HEADER_NODE_MAX + 1];
+
+	node = kzalloc(sizeof *node, GFP_KERNEL);
+	if (!node)
+		return ERR_PTR(-ENOMEM);
+
+	err = nla_parse_nested(attrs, NFL_HEADER_NODE_MAX,
+			       attr, flow_table_header_node_policy);
+	if (err)
+		goto err;
+
+	if (!attrs[NFL_HEADER_NODE_NAME] || !attrs[NFL_HEADER_NODE_UID] ||
+	    !attrs[NFL_HEADER_NODE_HDRS]) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	node->name = unft_encap_get_name(attrs[NFL_HEADER_NODE_NAME]);
+	if (!node->name) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	node->uid = nla_get_u32(attrs[NFL_HEADER_NODE_UID]);
+
+	node->hdrs = unft_encap_get_header_node_hdrs(attrs[NFL_HEADER_NODE_HDRS]);
+	if (IS_ERR(node->hdrs)) {
+		err = PTR_ERR(node->hdrs);
+		node->hdrs = NULL;
+		goto err;
+	}
+
+	node->jump = unft_encap_get_jump_tables(attrs[NFL_HEADER_NODE_JUMP]);
+	if (IS_ERR(node->jump)) {
+		err = PTR_ERR(node->jump);
+		node->jump = NULL;
+		goto err;
+	}
+
+	return node;
+err:
+	unft_encap_free_header_node(node);
+	return ERR_PTR(err);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_header_nodes(struct net_flow_hdr_node **nodes)
+{
+	int i;
+
+	if (!nodes)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(nodes[i]); i++)
+		unft_encap_free_header_node(nodes[i]);
+
+	kfree(nodes);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_header_graph(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+
+	if (!attr || unft_header_nodes)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_HEADER_GRAPH_NODE)
+			count++;
+
+	unft_header_nodes = kcalloc(count + 1, sizeof *unft_header_nodes,
+				  GFP_KERNEL);
+	if (!unft_header_nodes)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		if (nla_type(a) != NFL_HEADER_GRAPH_NODE)
+			continue;
+
+		unft_header_nodes[count] = unft_encap_get_header_node(a);
+		if (IS_ERR(unft_header_nodes[count])) {
+			int err = PTR_ERR(unft_header_nodes[count]);
+
+			unft_encap_free_header_nodes(unft_header_nodes);
+			unft_header_nodes = NULL;
+			return err;
+		}
+
+		count++;
+	}
+
+	return 0;
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_table_node(struct net_flow_tbl_node *node)
+{
+	kfree(node->jump);
+	kfree(node);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static const
+struct nla_policy flow_table_table_node_policy[NFL_TABLE_GRAPH_NODE_MAX + 1] =
+{
+        [NFL_TABLE_GRAPH_NODE_UID]	= { .type = NLA_U32 },
+        [NFL_TABLE_GRAPH_NODE_FLAGS]	= { .type = NLA_U32 },
+        [NFL_TABLE_GRAPH_NODE_JUMP]	= { .type = NLA_NESTED },
+};
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure */
+struct net_flow_tbl_node *unft_encap_get_table_node(struct nlattr *attr)
+{
+	int err;
+	struct net_flow_tbl_node *node;
+	struct nlattr *attrs[NFL_TABLE_GRAPH_NODE_MAX + 1];
+
+	node = kzalloc(sizeof *node, GFP_KERNEL);
+	if (!node)
+		return ERR_PTR(-ENOMEM);
+
+	err = nla_parse_nested(attrs, NFL_TABLE_GRAPH_NODE_MAX,
+			       attr, flow_table_table_node_policy);
+	if (err)
+		goto err;
+
+	if (!attrs[NFL_TABLE_GRAPH_NODE_UID] ||
+	    !attrs[NFL_TABLE_GRAPH_NODE_FLAGS]) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	node->uid = nla_get_u32(attrs[NFL_TABLE_GRAPH_NODE_UID]);
+	node->flags = nla_get_u32(attrs[NFL_TABLE_GRAPH_NODE_FLAGS]);
+
+	node->jump = unft_encap_get_jump_tables(attrs[NFL_TABLE_GRAPH_NODE_JUMP]);
+	if (IS_ERR(node->jump)) {
+		err = PTR_ERR(node->jump);
+		node->jump = NULL;
+		goto err;
+	}
+
+	return node;
+err:
+	unft_encap_free_table_node(node);
+	return ERR_PTR(err);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static void unft_encap_free_table_nodes(struct net_flow_tbl_node **nodes)
+{
+	int i;
+
+	if (!nodes)
+		return;
+
+	for (i = 0; !IS_ERR_OR_NULL(nodes[i]); i++)
+		unft_encap_free_table_node(nodes[i]);
+
+	kfree(nodes);
+}
+
+/* This only deals with encoding NFT attibutes and could
+ * be part of flow table infrastructure.
+ */
+static int unft_encap_get_table_graph(struct nlattr *attr)
+{
+	int count, rem;
+	struct nlattr *a;
+
+	if (!attr || unft_table_nodes)
+		return -EINVAL;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem)
+		if (nla_type(a) == NFL_TABLE_GRAPH_NODE)
+			count++;
+
+	unft_table_nodes = kcalloc(count + 1, sizeof *unft_table_nodes,
+				   GFP_KERNEL);
+	if (!unft_table_nodes)
+		return -ENOMEM;
+
+	count = 0;
+	nla_for_each_nested(a, attr, rem) {
+		if (nla_type(a) != NFL_TABLE_GRAPH_NODE)
+			continue;
+
+		unft_table_nodes[count] = unft_encap_get_table_node(a);
+		if (IS_ERR(unft_table_nodes[count])) {
+			int err = PTR_ERR(unft_table_nodes[count]);
+
+			unft_encap_free_table_nodes(unft_table_nodes);
+			unft_table_nodes = NULL;
+			return err;
+		}
+
+		count++;
+	}
+
+	return 0;
+}
+
+static const
+struct nla_policy unft_net_flow_policy[NFL_MAX + 1] = {
+	[NFL_IDENTIFIER_TYPE]	= { .type = NLA_U32,},
+	[NFL_IDENTIFIER]	= { .type = NLA_U32,},
+	[NFL_TABLES]		= { .type = NLA_NESTED,},
+	[NFL_HEADERS]		= { .type = NLA_NESTED,},
+	[NFL_ACTIONS]		= { .type = NLA_NESTED,},
+	[NFL_HEADER_GRAPH]	= { .type = NLA_NESTED,},
+	[NFL_TABLE_GRAPH]	= { .type = NLA_NESTED,},
+	[NFL_FLOWS]		= { .type = NLA_NESTED,},
+	[NFL_FLOWS_ERROR]	= { .type = NLA_NESTED,},
+};
+
+static int unft_encap_net_flow_cmd(u32 cmd, struct nlattr *attr)
+{
+	int err;
+	struct nlattr *tb[NFL_MAX + 1];
+	u32 ifindex, type;
+
+	if (!attr)
+		return -EINVAL;
+
+	err = nla_parse_nested(tb, NFL_MAX, attr, unft_net_flow_policy);
+	if (err)
+		return err;
+
+	if (!tb[NFL_IDENTIFIER_TYPE] || !tb[NFL_IDENTIFIER])
+		return -EINVAL;
+	type = nla_get_u32(tb[NFL_IDENTIFIER_TYPE]);
+	if (type != NFL_IDENTIFIER_IFINDEX)
+		return -EOPNOTSUPP;
+	ifindex = nla_get_u32(tb[NFL_IDENTIFIER]);
+
+	pr_debug("%s type: %u ifindex: %u cmd: %u\n", __func__, type,
+		 ifindex, cmd);
+
+	switch (cmd) {
+	case NFL_TABLE_CMD_GET_TABLES:
+		return unft_encap_get_tables(tb[NFL_TABLES]);
+
+	case NFL_TABLE_CMD_GET_HEADERS:
+		return unft_encap_get_headers(tb[NFL_HEADERS]);
+
+	case NFL_TABLE_CMD_GET_ACTIONS:
+		return unft_encap_get_actions(tb[NFL_ACTIONS]);
+
+	case NFL_TABLE_CMD_GET_HDR_GRAPH:
+		return unft_encap_get_header_graph(tb[NFL_HEADER_GRAPH]);
+
+	case NFL_TABLE_CMD_GET_TABLE_GRAPH:
+		return unft_encap_get_table_graph(tb[NFL_TABLE_GRAPH]);
+
+	case NFL_TABLE_CMD_SET_FLOWS:
+	case NFL_TABLE_CMD_DEL_FLOWS:
+		/* Noting more to decode for these commands */
+		return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static const
+struct nla_policy net_flow_hairpin_encap_policy[NFLH_ENCAP_MAX + 1] = {
+	[NFLH_ENCAP_CMD_TYPE]	= { .type = NLA_U32,},
+	[NFLH_ENCAP_CMD]	= { .type = NLA_U32,},
+	[NFLH_ENCAP_SEQ]	= { .type = NLA_U64,},
+	[NFLH_ENCAP_STATUS]	= { .type = NLA_U32,},
+	[NFLH_ENCAP_ATTR]	= { .type = NLA_NESTED,},
+};
+
+static int net_flow_table_hairpin_cmd_encap(struct sk_buff *skb,
+					    struct genl_info *info)
+{
+	int err = -EINVAL;
+	struct nlattr *tb[NFLH_ENCAP_MAX + 1];
+	u32 cmd, status, type;
+	u64 seq;
+
+	if (unft_msg_state != UNFT_MSG_S_REQUEST)
+		goto out;
+
+	if (!info->attrs[NFLH_ENCAP])
+		goto out;
+
+	err = nla_parse_nested(tb, NFLH_ENCAP_MAX,
+			       info->attrs[NFLH_ENCAP],
+			       net_flow_hairpin_encap_policy);
+	if (err)
+		goto out;
+
+	if (!tb[NFLH_ENCAP_CMD_TYPE] ||
+	    !tb[NFLH_ENCAP_CMD] ||
+	    !tb[NFLH_ENCAP_SEQ] ||
+	    !tb[NFLH_ENCAP_STATUS]) {
+		err = -EINVAL;
+		goto out;
+	}
+	type = nla_get_u32(tb[NFLH_ENCAP_CMD_TYPE]);
+	if (type != NFLH_ENCAP_CMD_NFL_CMD) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+	cmd = nla_get_u32(tb[NFLH_ENCAP_CMD]);
+	seq = nla_get_u64(tb[NFLH_ENCAP_SEQ]);
+	status = nla_get_u32(tb[NFLH_ENCAP_STATUS]);
+
+	if (unft_msg_seq != seq) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	pr_debug("%s cmd: %u seq: %llu status: %u\n", __func__,
+		 cmd, seq, status);
+
+	switch (status) {
+	case NFLH_ENCAP_STATUS_OK:
+		err = unft_encap_net_flow_cmd(cmd, tb[NFLH_ENCAP_ATTR]);
+		if (err)
+			goto out;
+		unft_msg_status = 0;
+		break;
+
+	case NFLH_ENCAP_STATUS_EINVAL:
+		unft_msg_status = -EINVAL;
+		break;
+
+	case NFLH_ENCAP_STATUS_EOPNOTSUPP:
+		unft_msg_status = -EOPNOTSUPP;
+		break;
+
+	default:
+		err = -EINVAL;
+		goto out;
+	}
+
+out:
+	unft_msg_state = UNFT_MSG_S_REPLY;
+	wake_up_interruptible(&unft_msg_wq);
+	return err;
+}
+
+static const struct genl_ops net_flow_table_hairpin_nl_ops[] = {
+	{
+		.cmd = NFLH_CMD_SET_LISTENER,
+		.doit = net_flow_table_hairpin_cmd_set_listener,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NFLH_CMD_GET_LISTENER,
+		.doit = net_flow_table_hairpin_cmd_get_listener,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NFLH_CMD_ENCAP,
+		.doit = net_flow_table_hairpin_cmd_encap,
+		.flags = GENL_ADMIN_PERM,
+	},
+};
+
+static netdev_tx_t unft_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+
+	return NETDEV_TX_OK;
+}
+
+static int
+unft_flow_table_get_tables__(struct net_device *dev)
+{
+	int err, i;
+
+	err = unft_flow_encap_request(dev, NFL_TABLE_CMD_GET_TABLES,
+				      NULL, NULL);
+	if (err)
+		return err;
+
+	for (i = 0; unft_table_list[i]; i++) {
+		err = net_flow_init_cache(unft_table_list[i]);
+		if (err)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	while (i-- > 1)
+		net_flow_destroy_cache(unft_table_list[i - 1]);
+	return err;
+}
+
+static struct net_flow_tbl **unft_flow_table_get_tables(struct net_device *dev)
+{
+	if (!unft_table_list && unft_flow_table_get_tables__(dev))
+		return NULL;
+
+	return unft_table_list;
+}
+
+static struct net_flow_hdr **unft_flow_table_get_headers(struct net_device *dev)
+{
+	if (!unft_header_list &&
+	    unft_flow_encap_request(dev, NFL_TABLE_CMD_GET_HEADERS, NULL, NULL))
+		return NULL;
+
+	return unft_header_list;
+}
+
+static struct net_flow_action **unft_flow_table_get_actions(struct net_device *dev)
+{
+	if (!unft_action_list &&
+	    unft_flow_encap_request(dev, NFL_TABLE_CMD_GET_ACTIONS, NULL, NULL))
+		return NULL;
+
+	return unft_action_list;
+}
+
+static struct net_flow_hdr_node **unft_flow_table_get_hgraph(struct net_device *dev)
+{
+	if (!unft_header_nodes &&
+	    unft_flow_encap_request(dev, NFL_TABLE_CMD_GET_HDR_GRAPH,
+				    NULL, NULL))
+		return NULL;
+
+	return unft_header_nodes;
+}
+
+static struct net_flow_tbl_node **unft_flow_table_get_tgraph(struct net_device *dev)
+{
+	if (!unft_table_nodes &&
+	    unft_flow_encap_request(dev, NFL_TABLE_CMD_GET_TABLE_GRAPH,
+				    NULL, NULL))
+		return NULL;
+
+	return unft_table_nodes;
+}
+
+static const struct net_device_ops unft_ops = {
+	.ndo_start_xmit = unft_xmit, /* Required */
+	.ndo_flow_set_rule = unft_flow_table_set_rule,
+	.ndo_flow_del_rule = unft_flow_table_del_rule,
+	.ndo_flow_get_tbls = unft_flow_table_get_tables,
+	.ndo_flow_get_hdrs = unft_flow_table_get_headers,
+	.ndo_flow_get_actions = unft_flow_table_get_actions,
+	.ndo_flow_get_hdr_graph = unft_flow_table_get_hgraph,
+	.ndo_flow_get_tbl_graph = unft_flow_table_get_tgraph,
+};
+
+static void unft_setup(struct net_device *dev)
+{
+	dev->type = ARPHRD_NETLINK;
+	dev->tx_queue_len = 0;
+
+	dev->netdev_ops	= &unft_ops;
+	dev->destructor	= free_netdev;
+
+	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
+			NETIF_F_HIGHDMA | NETIF_F_LLTX;
+	dev->flags = IFF_NOARP;
+
+	/* That's rather a softlimit here, which, of course,
+	 * can be altered. Not a real MTU, but what is to be
+	 * expected in most cases.
+	 */
+	dev->mtu = NLMSG_GOODSIZE;
+}
+
+static int unft_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (tb[IFLA_ADDRESS])
+		return -EINVAL;
+	return 0;
+}
+
+static struct rtnl_link_ops unft_link_ops __read_mostly = {
+	.kind			= "unft",
+	.setup			= unft_setup,
+	.validate		= unft_validate,
+};
+static __init int unft_register(void)
+{
+	int err;
+
+	err = genl_register_family_with_ops(&net_flow_hairpin_nl_family,
+					    net_flow_table_hairpin_nl_ops);
+	if (err)
+		return err;
+
+	err = rtnl_link_register(&unft_link_ops);
+	if (err)
+		goto err;
+
+	return 0;
+
+err:
+	genl_unregister_family(&net_flow_hairpin_nl_family);
+	return err;
+}
+
+static __exit void unft_unregister(void)
+{
+	int i;
+
+	genl_unregister_family(&net_flow_hairpin_nl_family);
+	rtnl_link_unregister(&unft_link_ops);
+
+	for (i = 0; unft_table_list[i]; i++)
+		net_flow_destroy_cache(unft_table_list[i]);
+	unft_encap_free_tables(unft_table_list);
+	unft_encap_free_headers(unft_header_list);
+	unft_encap_free_actions(unft_action_list);
+	unft_encap_free_header_nodes(unft_header_nodes);
+	unft_encap_free_table_nodes(unft_table_nodes);
+}
+
+module_init(unft_register);
+module_exit(unft_unregister);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Simon Horman <simon.horman@netronome.com>");
+MODULE_DESCRIPTION("User-Space Hairpin Network Flow Table Device");
+MODULE_ALIAS_RTNL_LINK("unft");
+MODULE_ALIAS_GENL_FAMILY(NFLH_GENL_NAME);
-- 
2.1.4

^ permalink raw reply related

* [PATCH/RFC 2/3] net: flow: Introduce flow table hairpin API
From: Simon Horman @ 2015-02-18 19:25 UTC (permalink / raw)
  To: netdev; +Cc: Simon Horman
In-Reply-To: <1424287559-25700-1-git-send-email-simon.horman@netronome.com>

*** Not for Upstream Merge
*** For informational purposes only

This introduces an netlink API to allow the Flow API to be hairpined
back to user-space thus allowing the NDOs of the Flow API to be backed there.

This will be used by a follow-up patch.

Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
 include/linux/if_flow_hairpin.h      |   6 ++
 include/uapi/linux/if_flow_hairpin.h | 159 +++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+)
 create mode 100644 include/linux/if_flow_hairpin.h
 create mode 100644 include/uapi/linux/if_flow_hairpin.h

diff --git a/include/linux/if_flow_hairpin.h b/include/linux/if_flow_hairpin.h
new file mode 100644
index 0000000..d958f8d
--- /dev/null
+++ b/include/linux/if_flow_hairpin.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_IF_FLOW_HAIRPIN_H
+#define _LINUX_IF_FLOW_HAIRPIN_H
+
+#include <uapi/linux/if_flow_hairpin.h>
+
+#endif
diff --git a/include/uapi/linux/if_flow_hairpin.h b/include/uapi/linux/if_flow_hairpin.h
new file mode 100644
index 0000000..eb4cbd8
--- /dev/null
+++ b/include/uapi/linux/if_flow_hairpin.h
@@ -0,0 +1,159 @@
+/*
+ * include/uapi/linux/if_flow_hairpin.h -
+ * Hairpin to allow the messages of the Flow table interface for
+ * Swtich devices to be forwarded to user-space
+ * Copyright (c) 2014 Simon Horman <simon.horman@netronome.com>
+ *
+ * Based on: Flow table interface for Switch devices
+ * Copyright (c) 2014 John Fastabend <john.r.fastabend@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Author: Simon Horman <simon.horman@netronome.com>
+ */
+
+/* Netlink description:
+ *
+ * The NFL_* attributes contained in NFLH_ENCAP_ATTR
+ * should also include their nested attributes, as described in
+ * include/uapi/linux/if_flow.h.
+
+ * Set Listener <Request>,
+ * Get Listener <Request> and
+ * Get Listener <Reply> description.
+ *
+ * Set Listener registers netlink port ids to receive flow deletion
+ * notifications if the NFLH_LISTENER_ATTR_PIDS attribute is
+ * present. Otherwise it unregisters port ids if they were previously
+ * registered by a Set Listener with the
+ * NFLH_LISTENER_ATTR_PIDS attribute present.
+ *
+ * Get Listener reports the port ids if they were previously registered by
+ * a Set Listener with the NFLH_LISTENER_ATTR_PIDS.  If no ids
+ * are registered then the NFLH_LISTENER_ATTR_PIDS attribute of
+ * the reply should be omitted.
+ *
+ * The NFLH_LISTENER_ATTR_PIDS attribute is an array of u32
+ * values. If the attribute is present then it must contain at least one
+ * element. The implementation may choose to ignore some elements.
+ * Currently the implementation ignores all elements other than the first
+ * one.
+ *
+ *
+ * [NFLH_LISTENER]
+ *   [NFLH_LISTENER_ATTR_TYPE]
+ *   [NFLH_LISTENER_ATTR_PIDS]
+ *
+ * Message used to encapsulate both a NFL message forwardeded from
+ * the kernel to user-space as a notification, and the reply of processing
+ * that message sent from user-space to the kernel. In the case of the
+ * former NFLH_ENCAP_STATUS whould be omitted. In the case
+ * of the latter it should be included and its value should be 0 on success
+ * otherwise a negative error code.
+ *
+ * [NFLH_ENCAP]
+ *   [NFLH_ENCAP_CMD_TYPE]
+ *   [NFLH_ENCAP_CMD]
+ *   [NFLH_ENCAP_SEQ]
+ *   [NFLH_ENCAP_STATUS]
+ *   [NFLH_ENCAP_ATTR]
+ *     [NFL_TABLES]
+ *     [NFL_HEADERS]
+ *     [NFL_ACTIONS]
+ *     [NFL_HEADER_GRAPH]
+ *     [NFL_TABLE_GRAPH]
+ *     [NFL_FLOWS]
+ *     [NFL_FLOWS_ERROR]
+ */
+
+#ifndef _UAPI_LINUX_IF_FLOW_HAIRPIN
+#define _UAPI_LINUX_IF_FLOW_HAIRPIN
+
+#include <linux/types.h>
+
+/**
+ * @struct net_flow_hairpin_encap_header
+ * @brief defines the header of an encapsulated message
+ *
+ * @cmd_type: type of inner command
+ * @cmd: identifier of inner command
+ * @status: status of command execution
+ * @seq: sequence number of request
+ */
+struct net_flow_hairpin_encap_header {
+	__u32 cmd_type;
+	__u32 cmd;
+	__u64 seq;
+	__s32 status;
+};
+
+enum {
+	NFLH_LISTENER_ATTR_TYPE_ENCAP,
+};
+
+enum {
+	NFLH_LISTENER_ATTR_UNSPEC,
+	NFLH_LISTENER_ATTR_TYPE,
+	NFLH_LISTENER_ATTR_PIDS,
+	__NFLH_LISTENER_ATTR_MAX,
+};
+#define NFLH_LISTENER_ATTR_MAX (__NFLH_LISTENER_ATTR_MAX - 1)
+
+enum {
+	/* A Net Flow Table Command is used */
+	NFLH_ENCAP_CMD_NFL_CMD,
+};
+
+enum {
+	/* A Net Flow Table Command is used */
+	NFLH_ENCAP_STATUS_OK,
+	NFLH_ENCAP_STATUS_EINVAL,
+	NFLH_ENCAP_STATUS_EOPNOTSUPP,
+};
+
+enum {
+	NFLH_ENCAP_UNSPEC,
+	NFLH_ENCAP_CMD_TYPE,
+	NFLH_ENCAP_CMD,
+	NFLH_ENCAP_SEQ,
+	NFLH_ENCAP_STATUS,
+	NFLH_ENCAP_ATTR,
+	__NFLH_ENCAP_MAX,
+};
+#define NFLH_ENCAP_MAX (__NFLH_ENCAP_MAX - 1)
+
+enum {
+	NFLH_UNSPEC,
+
+	NFLH_ENCAP,
+	NFLH_LISTENER,
+
+	__NFLH_MAX,
+};
+#define NFLH_MAX (__NFLH_MAX - 1)
+
+enum {
+	/* Userspace commands. */
+	NFLH_CMD_SET_LISTENER,
+	NFLH_CMD_GET_LISTENER,
+
+	/* Both userspace commands and Kernel-to-user notifications. */
+	NFLH_CMD_ENCAP,
+
+	__NFLH_CMD_MAX,
+	NFLH_CMD_MAX = (__NFLH_CMD_MAX - 1),
+};
+
+#define NFLH_GENL_NAME "net_flow_hp"
+#define NFLH_GENL_VERSION 0x1
+#endif /* _UAPI_LINUX_IF_FLOW_HAIRPIN */
-- 
2.1.4

^ permalink raw reply related

* [PATCH/RFC 1/3] net: flow: export net_flow_{put_rule,get_{field,action}}
From: Simon Horman @ 2015-02-18 19:25 UTC (permalink / raw)
  To: netdev; +Cc: Simon Horman
In-Reply-To: <1424287559-25700-1-git-send-email-simon.horman@netronome.com>

*** Not for Upstream Merge
*** For informational purposes only

This is to allow these functions to be used by a new driver, unft,
which will be proposed in a subsequent patch.

Signed-off-by: Simon Horman <simon.horman@netronome.com>
---
 include/linux/if_flow.h |  6 ++++++
 net/core/flow_table.c   | 10 ++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/include/linux/if_flow.h b/include/linux/if_flow.h
index dc70e3e..eb19b6c8 100644
--- a/include/linux/if_flow.h
+++ b/include/linux/if_flow.h
@@ -225,4 +225,10 @@ net_flow_destroy_cache(struct net_flow_tbl *table)
 	return;
 }
 #endif /* CONFIG_NET_FLOW_TABLES */
+
+struct nlattr;
+
+int net_flow_put_rule(struct sk_buff *skb, struct net_flow_rule *rule);
+int net_flow_get_field(struct net_flow_field_ref *field, struct nlattr *nla);
+int net_flow_get_action(struct net_flow_action *action, struct nlattr *nla);
 #endif /* _IF_FLOW_H_ */
diff --git a/net/core/flow_table.c b/net/core/flow_table.c
index a938929..8c26019 100644
--- a/net/core/flow_table.c
+++ b/net/core/flow_table.c
@@ -975,7 +975,7 @@ done:
 	return 0;
 }
 
-static int net_flow_put_rule(struct sk_buff *skb, struct net_flow_rule *rule)
+int net_flow_put_rule(struct sk_buff *skb, struct net_flow_rule *rule)
 {
 	struct nlattr *flows, *actions, *matches;
 	int j, i = 0;
@@ -1039,6 +1039,7 @@ flows_put_failure:
 put_failure:
 	return err;
 }
+EXPORT_SYMBOL(net_flow_put_rule);
 
 static int net_flow_get_rule_cache(struct sk_buff *skb,
 				   struct net_flow_tbl *table,
@@ -1233,8 +1234,7 @@ const struct nla_policy net_flow_field_policy[NFL_FIELD_REF_MAX + 1] = {
 				      .len = sizeof(u64)},
 };
 
-static int net_flow_get_field(struct net_flow_field_ref *field,
-			      struct nlattr *nla)
+int net_flow_get_field(struct net_flow_field_ref *field, struct nlattr *nla)
 {
 	struct nlattr *ref[NFL_FIELD_REF_MAX+1];
 	int err;
@@ -1332,6 +1332,7 @@ static int net_flow_get_field(struct net_flow_field_ref *field,
 
 	return err;
 }
+EXPORT_SYMBOL(net_flow_get_field);
 
 static void net_flow_free_actions(struct net_flow_action *actions)
 {
@@ -1420,7 +1421,7 @@ static int net_flow_get_actarg(struct net_flow_action_arg *arg,
 	return 0;
 }
 
-static int net_flow_get_action(struct net_flow_action *a, struct nlattr *attr)
+int net_flow_get_action(struct net_flow_action *a, struct nlattr *attr)
 {
 	struct nlattr *act[NFL_ACTION_ATTR_MAX+1];
 	struct nlattr *args;
@@ -1470,6 +1471,7 @@ static int net_flow_get_action(struct net_flow_action *a, struct nlattr *attr)
 	}
 	return 0;
 }
+EXPORT_SYMBOL(net_flow_get_action);
 
 static const
 struct nla_policy net_flow_rule_policy[NFL_ATTR_MAX + 1] = {
-- 
2.1.4

^ permalink raw reply related

* [PATCH/RFC 0/3] net: unft: Add Userspace hairpin network flow table device
From: Simon Horman @ 2015-02-18 19:25 UTC (permalink / raw)
  To: netdev; +Cc: Simon Horman

*** Not for Upstream Merge
*** For informational purposes only

As discussed at netconf we have been working on hairpinning Flow API
messages back to user-space as a mechanism for exercising that API.

And as promised at netconf I am releasing our code.

What this can do:
* Allow the implementation of the NDO's proposed by John Fastabend's API
  to be implemented in user-space. This is done using netlink messages.

What this cannot do:
* Anything else

Limitations:
* Both the design and the implementation are slow

I have also written user-space code. There are two portions:

1. flow-table

   This may be used to send and receive messages from the Flow API.
   It a command-line utility which may be used to exercise the flow API.
   And a library to help achieve this. An interesting portion
   of the library is a small framework for converting between
   netlink and JSON.

   It is available here: https://github.com/horms/flow-table
   The licence is GPLv2

   It overlaps to some extent with user-space code by John Fastabend.
   I was not aware of that work which he was doing concurrently.

2. flow-table-hairpin

   This is a daemon that listens for messages hairpined back
   to user-space and responds accordingly. That is, the user-space
   backing of the NDOs of the Flow API.

   It includes a simple flow table backend (ftbe) abstraction
   and a dummy implementation that stores flows in a local list
   ** and does nothing else with them ***

   It is available here: https://github.com/horms/flow-table-hairpin
   The licence is GPLv2


Usage example:

# Create unft netdev
ip link add type unft

# Start haripind. The tables, headers, etc... are provided as JSON
flow-table-hairpind \
        --tables tables.json \
        --headers headers.json \
        --actions actions.json \
        --header-graph header-graph.json \
        --table-graph table-graph.json &

# Get the tables of unft using the Flow API
flow-table-ctl get-tables unft0


Base:

These patches are based on v2 of the Flow API.
"[net-next PATCH v2 00/12] Flow API"
http://www.spinics.net/lists/netdev/msg311961.html


Simon Horman (3):
  net: flow: export net_flow_{put_rule,get_{field,action}}
  net: flow: Introduce flow table hairpin API
  net: unft: Add Userspace hairpin network flow table device

 drivers/net/Kconfig                  |    9 +
 drivers/net/Makefile                 |    1 +
 drivers/net/unft.c                   | 1520 ++++++++++++++++++++++++++++++++++
 include/linux/if_flow.h              |    6 +
 include/linux/if_flow_hairpin.h      |    6 +
 include/uapi/linux/if_flow_hairpin.h |  159 ++++
 net/core/flow_table.c                |   10 +-
 7 files changed, 1707 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/unft.c
 create mode 100644 include/linux/if_flow_hairpin.h
 create mode 100644 include/uapi/linux/if_flow_hairpin.h

-- 
2.1.4

^ permalink raw reply

* Re: [PATCH] net: phy: Fix verification of EEE support in phy_init_eee
From: Florian Fainelli @ 2015-02-18 19:01 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: netdev, Giuseppe Cavallaro
In-Reply-To: <1424194582-9792-1-git-send-email-linux@roeck-us.net>

On 17/02/15 09:36, Guenter Roeck wrote:
> phy_init_eee uses phy_find_setting(phydev->speed, phydev->duplex)
> to find a valid entry in the settings array for the given speed
> and duplex value. For full duplex 1000baseT, this will return
> the first matching entry, which is the entry for 1000baseKX_Full.
> 
> If the phy eee does not support 1000baseKX_Full, this entry will not
> match, causing phy_init_eee to fail for no good reason.
> 
> Fixes: 9a9c56cb34e6 ("net: phy: fix a bug when verify the EEE support")
> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>

Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Fixes: 3e7077067e80c ("phy: Expand phy speed/duplex settings array")

> ---
> I have another version where phy_check_valid() is open coded. It looks a bit
> messy to me, but I don't really mind either way if that is preferred.
> 
>  drivers/net/phy/phy.c | 23 ++++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index cdcac6a..52cd8db 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -236,6 +236,25 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
>  }
>  
>  /**
> + * phy_check_valid - check if there is a valid PHY setting which matches
> + *		     speed, duplex, and feature mask
> + * @speed: speed to match
> + * @duplex: duplex to match
> + * @features: A mask of the valid settings
> + *
> + * Description: Returns true if there is a valid setting, false otherwise.
> + */
> +static inline bool phy_check_valid(int speed, int duplex, u32 features)
> +{
> +	unsigned int idx;
> +
> +	idx = phy_find_valid(phy_find_setting(speed, duplex), features);
> +
> +	return settings[idx].speed == speed && settings[idx].duplex == duplex &&
> +		(settings[idx].setting & features);
> +}
> +
> +/**
>   * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
>   * @phydev: the target phy_device struct
>   *
> @@ -1045,7 +1064,6 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
>  		int eee_lp, eee_cap, eee_adv;
>  		u32 lp, cap, adv;
>  		int status;
> -		unsigned int idx;
>  
>  		/* Read phy status to properly get the right settings */
>  		status = phy_read_status(phydev);
> @@ -1077,8 +1095,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
>  
>  		adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
>  		lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
> -		idx = phy_find_setting(phydev->speed, phydev->duplex);
> -		if (!(lp & adv & settings[idx].setting))
> +		if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv))
>  			goto eee_exit_err;
>  
>  		if (clk_stop_enable) {
> 


-- 
Florian

^ permalink raw reply

* Re: getting a list of naked interface names from iproute2
From: Cong Wang @ 2015-02-18 18:55 UTC (permalink / raw)
  To: mthode; +Cc: Stephen Hemminger, netdev
In-Reply-To: <54E418D2.3020406@mthode.org>

On Tue, Feb 17, 2015 at 8:45 PM, Matthew Thode <mthode@mthode.org> wrote:
> Do you happen to know a way to request it for a specific namespace?
> going over the links in /sys/class/net only gets you the current
> namespace (was the easiest method to do in python2.7).

The interface is not friendly. You need to open an fd which points to the
netns proc file or the pid of a task inside the namespace, take a look at how
`ip netns exec` is implemented.

^ permalink raw reply

* [PATCH -stable] ath6kl: fix struct hif_scatter_req list handling
From: Josh Cartwright @ 2015-02-18 17:17 UTC (permalink / raw)
  To: Kalle Valo, Greg Kroah-Hartman
  Cc: John W. Linville, linux-wireless, netdev, linux-kernel, stable,
	Jason Liu

From: Kalle Valo <kvalo@qca.qualcomm.com>

commit 31b9cc9a873dcab161999622314f98a75d838975 upstream.

Jason noticed that with Yocto GCC 4.8.1 ath6kl crashes with this iperf command:

iperf -c $TARGET_IP -i 5 -t 50 -w 1M

The crash was:

Unable to handle kernel paging request at virtual address 1a480000
pgd = 80004000
[1a480000] *pgd=00000000
Internal error: Oops: 805 [#1] SMP ARM
Modules linked in: ath6kl_sdio ath6kl_core [last unloaded: ath6kl_core]
CPU: 0 PID: 1953 Comm: kworker/u4:0 Not tainted 3.10.9-1.0.0_alpha+dbf364b #1
Workqueue: ath6kl ath6kl_sdio_write_async_work [ath6kl_sdio]
task: dcc9a680 ti: dc9ae000 task.ti: dc9ae000
PC is at v7_dma_clean_range+0x20/0x38
LR is at dma_cache_maint_page+0x50/0x54
pc : [<8001a6f8>]    lr : [<800170fc>]    psr: 20000093
sp : dc9afcf8  ip : 8001a748  fp : 00000004
r10: 00000000  r9 : 00000001  r8 : 00000000
r7 : 00000001  r6 : 00000000  r5 : 80cb7000  r4 : 03f9a480
r3 : 0000001f  r2 : 00000020  r1 : 1a480000  r0 : 1a480000
Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c53c7d  Table: 6cc5004a  DAC: 00000015
Process kworker/u4:0 (pid: 1953, stack limit = 0xdc9ae238)
Stack: (0xdc9afcf8 to 0xdc9b0000)
fce0:                                                       80c9b29c 00000000
fd00: 00000000 80017134 8001a748 dc302ac0 00000000 00000000 dc454a00 80c12ed8
fd20: dc115410 80017238 00000000 dc454a10 00000001 80017588 00000001 00000000
fd40: 00000000 dc302ac0 dc9afe38 dc9afe68 00000004 80c12ed8 00000000 dc454a00
fd60: 00000004 80436f88 00000000 00000000 00000600 0000ffff 0000000c 80c113c4
fd80: 80c9b29c 00000001 00000004 dc115470 60000013 dc302ac0 dc46e000 dc302800
fda0: dc9afe10 dc302b78 60000013 dc302ac0 dc46e000 00000035 dc46e5b0 80438c90
fdc0: dc9afe10 dc302800 dc302800 dc9afe68 dc9afe38 80424cb4 00000005 dc9afe10
fde0: dc9afe20 80424de8 dc9afe10 dc302800 dc46e910 80424e90 dc473c00 dc454f00
fe00: 000001b5 7f619d64 dcc7c830 00000000 00000000 dc9afe38 dc9afe68 00000000
fe20: 00000000 00000000 dc9afe28 dc9afe28 80424d80 00000000 00000035 9cac0034
fe40: 00000000 00000000 00000000 00000000 000001b5 00000000 00000000 00000000
fe60: dc9afe68 dc9afe10 3b9aca00 00000000 00000080 00000034 00000000 00000100
fe80: 00000000 00000000 dc9afe10 00000004 dc454a00 00000000 dc46e010 dc46e96c
fea0: dc46e000 dc46e964 00200200 00100100 dc46e910 7f619ec0 00000600 80c0e770
fec0: dc15a900 dcc7c838 00000000 dc46e954 8042d434 dcc44680 dc46e954 dc004400
fee0: dc454500 00000000 00000000 dc9ae038 dc004400 8003c450 dcc44680 dc004414
ff00: dc46e954 dc454500 00000001 dcc44680 dc004414 dcc44698 dc9ae000 dc9ae030
ff20: 00000001 dc9ae000 dc004400 8003d158 8003d020 00000000 00000000 80c53941
ff40: dc9aff64 dcb71ea0 00000000 dcc44680 8003d020 00000000 00000000 00000000
ff60: 00000000 80042480 00000000 00000000 000000f8 dcc44680 00000000 00000000
ff80: dc9aff80 dc9aff80 00000000 00000000 dc9aff90 dc9aff90 dc9affac dcb71ea0
ffa0: 800423cc 00000000 00000000 8000e018 00000000 00000000 00000000 00000000
ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[<8001a6f8>] (v7_dma_clean_range+0x20/0x38) from [<800170fc>] (dma_cache_maint_page+0x50/0x54)
[<800170fc>] (dma_cache_maint_page+0x50/0x54) from [<80017134>] (__dma_page_cpu_to_dev+0x34/0x9c)
[<80017134>] (__dma_page_cpu_to_dev+0x34/0x9c) from [<80017238>] (arm_dma_map_page+0x64/0x68)
[<80017238>] (arm_dma_map_page+0x64/0x68) from [<80017588>] (arm_dma_map_sg+0x7c/0xf4)
[<80017588>] (arm_dma_map_sg+0x7c/0xf4) from [<80436f88>] (sdhci_send_command+0x894/0xe00)
[<80436f88>] (sdhci_send_command+0x894/0xe00) from [<80438c90>] (sdhci_request+0xc0/0x1ec)
[<80438c90>] (sdhci_request+0xc0/0x1ec) from [<80424cb4>] (mmc_start_request+0xb8/0xd4)
[<80424cb4>] (mmc_start_request+0xb8/0xd4) from [<80424de8>] (__mmc_start_req+0x60/0x84)
[<80424de8>] (__mmc_start_req+0x60/0x84) from [<80424e90>] (mmc_wait_for_req+0x10/0x20)
[<80424e90>] (mmc_wait_for_req+0x10/0x20) from [<7f619d64>] (ath6kl_sdio_scat_rw.isra.10+0x1dc/0x240 [ath6kl_sdio])
[<7f619d64>] (ath6kl_sdio_scat_rw.isra.10+0x1dc/0x240 [ath6kl_sdio]) from [<7f619ec0>] (ath6kl_sdio_write_async_work+0x5c/0x104 [ath6kl_sdio])
[<7f619ec0>] (ath6kl_sdio_write_async_work+0x5c/0x104 [ath6kl_sdio]) from [<8003c450>] (process_one_work+0x10c/0x370)
[<8003c450>] (process_one_work+0x10c/0x370) from [<8003d158>] (worker_thread+0x138/0x3fc)
[<8003d158>] (worker_thread+0x138/0x3fc) from [<80042480>] (kthread+0xb4/0xb8)
[<80042480>] (kthread+0xb4/0xb8) from [<8000e018>] (ret_from_fork+0x14/0x3c)
Code: e1a02312 e2423001 e1c00003 f57ff04f (ee070f3a)
---[ end trace 0c038f0b8e0b67a3 ]---
Kernel panic - not syncing: Fatal exception

Jason's analysis:

  "The GCC 4.8.1 compiler will not do the for-loop till scat_entries, instead,
   it only run one round loop. This may be caused by that the GCC 4.8.1 thought
   that the scat_list only have one item and then no need to do full iteration,
   but this is simply wrong by looking at the assebly code. This will cause the sg
   buffer not get set when scat_entries > 1 and thus lead to kernel panic.

   Note: This issue not observed with GCC 4.7.2, only found on the GCC 4.8.1)"

Fix this by using the normal [0] style for defining unknown number of list
entries following the struct. This also fixes corruption with scat_q_depth, which
was mistankely added to the end of struct and overwritten if there were more
than item in the scat list.

Reported-by: Jason Liu <r64343@freescale.com>
Tested-by: Jason Liu <r64343@freescale.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
---
We ran into this issue in the 3.14.y stable tree which has been fixed upstream
since 3.16.  Please consider pulling it back to 3.14.y at least;  it may be
relevant further back, but it isn't clear when the issue first cropped up.  I'm
hoping Kalle can comment.

Thanks,
  Josh

 drivers/net/wireless/ath/ath6kl/hif.h  | 4 ++--
 drivers/net/wireless/ath/ath6kl/sdio.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
index 61f6b21..dc6bd8c 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.h
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -197,9 +197,9 @@ struct hif_scatter_req {
 	/* bounce buffer for upper layers to copy to/from */
 	u8 *virt_dma_buf;
 
-	struct hif_scatter_item scat_list[1];
-
 	u32 scat_q_depth;
+
+	struct hif_scatter_item scat_list[0];
 };
 
 struct ath6kl_irq_proc_registers {
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 7126bdd..6bf15a3 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -348,7 +348,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
 	int i, scat_req_sz, scat_list_sz, size;
 	u8 *virt_buf;
 
-	scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
+	scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item);
 	scat_req_sz = sizeof(*s_req) + scat_list_sz;
 
 	if (!virt_scat)
-- 
2.3.0

^ permalink raw reply related

* Re: [PATCH v2 2/3] Packet sniffer core framework
From: Stathis Voukelatos @ 2015-02-18 16:44 UTC (permalink / raw)
  To: Daniel Borkmann, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: abrestic-F7+t8E8rja9g9hUCZPvPmw,
	richardcochran-Re5JQEeQqe8AvxtiuMwx3w
In-Reply-To: <54E4B2CE.2090104-FeC+5ew28dpmcu3hnIyYJQ@public.gmane.org>

Hi Daniel,

On 18/02/15 15:42, Daniel Borkmann wrote:
>
> This whole framework really looks like only tailored to your specific
> driver, I have no idea who else should reuse that?! So, I don't think
> putting this under drivers/net/pkt-sniffer/ is a good idea.
>

Yes, it is not necessarilly expected to be used by other 3rd party 
drivers. The reason of splitting out the framework code is to account of 
the fact the we may develop in the future othersimilar sniffer H/W for 
non-ethernet interfaces (eg. wifi).
I can move the code under drivers/net/ethernet/linn as you mention 
below, although that may not account for non-ethernet backends in the
future.

> Also it looks slightly confusing as if I understand you correctly, your
> module's purpose is to pass down some "packet pattern" to the hardware
> and match that in order to get a precise timestamp in return?
>

Yes, this point can be slightly confusing. A write to a packet socket 
bound to the interface is done to supply the command string to the 
sniffer H/W, while reads would return matched packet bytes + timestamps 
(throuch cmsg). Is there any other way to supply the command string 
except of a proprietary ioctl?

> Might perhaps be better to have everything vendor-specific under something
> like drivers/net/ethernet/linn/ and have the framework squashed into the
> driver itself (if parts cannot be generalized in net/packet/).
>

Answered above.

> It would be good if you can also avoid the extra uapi export. Perhaps
> it's possible to reuse at least some of the existing timestamping
> infrastructure?

I can remove that. The header file only contains the list of commands.
They can be documented. The driver does use the existing timestamping
infrastructure to return timestamps to user space.

Thank you,
Stathis
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Use-after-free oops in next-20150204 - probably nelink related
From: Shachar Raindel @ 2015-02-18 15:52 UTC (permalink / raw)
  To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

Hi,

I'm running trinity inside a VM running linux-next tagged next-20150204.

The kernel debugging infrastructure detected a use-after-free situation, probably in netlink:

[25041.653858] =============================================================================
[25041.654502] BUG kmalloc-2048 (Not tainted): Poison overwritten
[25041.654502] -----------------------------------------------------------------------------
[25041.654502] 
[25041.654502] Disabling lock debugging due to kernel taint
[25041.654502] INFO: 0xffff88007a213f88-0xffff88007a213f8f. First byte 0x19 instead of 0x6b
[25041.654502] INFO: Allocated in sk_prot_alloc+0xcb/0x1b0 age=4824 cpu=0 pid=950
[25041.654502] 	__slab_alloc+0x4dc/0x586
[25041.654502] 	__kmalloc+0x3f8/0x480
[25041.654502] 	sk_prot_alloc+0xcb/0x1b0
[25041.654502] 	sk_alloc+0x30/0x2e0
[25041.654502] 	__netlink_create+0x37/0xe0
[25041.654502] 	netlink_create+0xea/0x250
[25041.654502] 	__sock_create+0x2a3/0x3c0
[25041.654502] 	SyS_socket+0x61/0xf0
[25041.654502] 	tracesys_phase2+0xd8/0xdd
[25041.654502] INFO: Freed in __sk_free+0x178/0x1c0 age=4687 cpu=0 pid=9
[25041.654502] 	__slab_free+0x55/0x242
[25041.654502] 	kfree+0x369/0x380
[25041.654502] 	__sk_free+0x178/0x1c0
[25041.654502] 	sk_free+0x19/0x20
[25041.654502] 	deferred_put_nlk_sk+0x20/0x30
[25041.654502] 	rcu_nocb_kthread+0x24b/0x630
[25041.654502] 	kthread+0x10d/0x130
[25041.654502] 	ret_from_fork+0x7c/0xb0
[25041.654502] INFO: Slab 0xffffea0001e88400 objects=13 used=13 fp=0x          (null) flags=0x1fffff80004080
[25041.654502] INFO: Object 0xffff88007a2137b0 @offset=14256 fp=0xffff88007a210000
[25041.654502] 
[25041.654502] Bytes b4 ffff88007a2137a0: d8 ee aa 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a  ........ZZZZZZZZ
[25041.654502] Object ffff88007a2137b0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2137c0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2137d0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2137e0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2137f0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213800: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213810: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213820: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213830: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213840: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213850: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213860: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213870: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213880: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213890: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138a0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138b0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138c0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138d0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138e0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2138f0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213900: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213910: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213920: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213930: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213940: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213950: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213960: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213970: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213980: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213990: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139a0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139b0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139c0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139d0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139e0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a2139f0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a80: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213a90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213aa0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ab0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ac0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ad0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ae0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213af0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b80: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213b90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ba0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213bb0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213bc0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213bd0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213be0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213bf0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c80: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213c90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ca0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213cb0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213cc0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213cd0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ce0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213cf0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d80: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213d90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213da0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213db0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213dc0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213dd0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213de0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213df0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e80: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213e90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ea0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213eb0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ec0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ed0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ee0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213ef0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f00: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f10: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f20: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f30: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f40: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f50: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f60: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f70: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213f80: 6b 6b 6b 6b 6b 6b 6b 6b 19 00 00 00 00 00 00 00  kkkkkkkk........
[25041.654502] Object ffff88007a213f90: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[25041.654502] Object ffff88007a213fa0: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
[25041.654502] Redzone ffff88007a213fb0: bb bb bb bb bb bb bb bb                          ........
[25041.654502] Padding ffff88007a2140f0: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
[25041.654502] CPU: 2 PID: 16599 Comm: top Tainted: G    B           3.19.0-rc7-next-20150204+ #28
[25041.654502] Hardware name: Red Hat KVM, BIOS Bochs 01/01/2007
[25041.654502]  0000000000000000 000000007af2d0f6 ffff8800048ab448 ffffffff8175d68e
[25041.654502]  0000000000000000 ffff88007ec04f00 ffff8800048ab488 ffffffff812287ad
[25041.654502]  0000000000000008 ffff880000000001 ffff88007a213f90 ffff88007ec04f00
[25041.654502] Call Trace:
[25041.654502]  [<ffffffff8175d68e>] dump_stack+0x4c/0x65
[25041.654502]  [<ffffffff812287ad>] print_trailer+0x14d/0x200
[25041.654502]  [<ffffffff8122892f>] check_bytes_and_report+0xcf/0x110
[25041.654502]  [<ffffffff81229ba7>] check_object+0x1d7/0x250
[25041.654502]  [<ffffffffa004e770>] ? alloc_indirect.isra.10+0x20/0x60 [virtio_ring]
[25041.654502]  [<ffffffff8175a830>] alloc_debug_processing+0x76/0x118
[25041.654502]  [<ffffffff8175b54d>] __slab_alloc+0x4dc/0x586
[25041.654502]  [<ffffffffa004e770>] ? alloc_indirect.isra.10+0x20/0x60 [virtio_ring]
[25041.654502]  [<ffffffff8122de28>] __kmalloc+0x3f8/0x480
[25041.654502]  [<ffffffffa004e770>] ? alloc_indirect.isra.10+0x20/0x60 [virtio_ring]
[25041.654502]  [<ffffffffa004e770>] alloc_indirect.isra.10+0x20/0x60 [virtio_ring]
[25041.654502]  [<ffffffff8122b889>] ? deactivate_slab+0x5a9/0x640
[25041.654502]  [<ffffffffa004e87e>] virtqueue_add_sgs+0xce/0x420 [virtio_ring]
[25041.654502]  [<ffffffffa0066492>] __virtblk_add_req+0xc2/0x1d0 [virtio_blk]
[25041.654502]  [<ffffffff810c7ba8>] ? sched_clock_cpu+0xa8/0xd0
[25041.654502]  [<ffffffff810c7c25>] ? local_clock+0x15/0x30
[25041.654502]  [<ffffffffa00666a7>] ? virtio_queue_rq+0x107/0x290 [virtio_blk]
[25041.654502]  [<ffffffffa00666a7>] ? virtio_queue_rq+0x107/0x290 [virtio_blk]
[25041.654502]  [<ffffffffa00666cb>] virtio_queue_rq+0x12b/0x290 [virtio_blk]
[25041.654502]  [<ffffffff8136661d>] __blk_mq_run_hw_queue+0x1fd/0x3c0
[25041.654502]  [<ffffffff81368e01>] ? blk_sq_make_request+0x231/0x5a0
[25041.654502]  [<ffffffff81367a20>] blk_mq_run_hw_queue+0xd0/0x110
[25041.654502]  [<ffffffff81368e20>] blk_sq_make_request+0x250/0x5a0
[25041.654502]  [<ffffffff81356990>] generic_make_request+0xe0/0x130
[25041.654502]  [<ffffffff81356a57>] submit_bio+0x77/0x150
[25041.654502]  [<ffffffff811f4a4a>] ? workingset_refault+0x5a/0xb0
[25041.654502]  [<ffffffff8129937a>] mpage_bio_submit+0x2a/0x40
[25041.654502]  [<ffffffff8129a539>] mpage_readpages+0x119/0x150
[25041.654502]  [<ffffffffa01984f0>] ? _ext4_get_block+0x220/0x220 [ext4]
[25041.654502]  [<ffffffffa01984f0>] ? _ext4_get_block+0x220/0x220 [ext4]
[25041.654502]  [<ffffffff8121ff97>] ? alloc_pages_current+0x107/0x1a0
[25041.654502]  [<ffffffffa0194bf4>] ext4_readpages+0x44/0x50 [ext4]
[25041.654502]  [<ffffffff811d16df>] __do_page_cache_readahead+0x2cf/0x350
[25041.654502]  [<ffffffff811d159b>] ? __do_page_cache_readahead+0x18b/0x350
[25041.654502]  [<ffffffff811c41e7>] filemap_fault+0x3b7/0x460
[25041.654502]  [<ffffffff811fd7e5>] ? handle_mm_fault+0xcd5/0x1700
[25041.654502]  [<ffffffff811f908c>] __do_fault+0x4c/0xd0
[25041.654502]  [<ffffffff811fd800>] handle_mm_fault+0xcf0/0x1700
[25041.654502]  [<ffffffff810e919f>] ? __lock_is_held+0x5f/0x90
[25041.654502]  [<ffffffff81071388>] __do_page_fault+0x1a8/0x470
[25041.654502]  [<ffffffff81071681>] do_page_fault+0x31/0x70
[25041.654502]  [<ffffffff8176a4d8>] page_fault+0x28/0x30
[25041.654502] FIX kmalloc-2048: Restoring 0xffff88007a213f88-0xffff88007a213f8f=0x6b
[25041.654502] 
[25041.654502] FIX kmalloc-2048: Marking all objects used
[25044.404089] ------------[ cut here ]------------
[25044.404792] WARNING: CPU: 0 PID: 5418 at fs/locks.c:243 locks_free_lock_context+0x64/0xc0()
[25044.406736] Modules linked in: 8021q garp mrp stp llc fuse cmtp kernelcapi bnep tun hidp crypto_user af_key rfcomm bluetooth vmw_vsock_vmci_transport vmw_vmci vsock l2tp_ppp l2tp_netlink l2tp_core ip6_udp_tunnel udp_tunnel pppoe pppox ppp_generic slhc scsi_transport_iscsi nfnetlink sctp libcrc32c ieee802154_socket ieee802154 atm nfsv3 rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache cfg80211 rfkill sg snd_hda_codec_generic snd_hda_intel snd_hda_controller dm_mirror snd_hda_codec dm_region_hash dm_log dm_mod snd_hwdep snd_seq snd_seq_device ppdev snd_pcm snd_timer snd virtio_balloon serio_raw pcspkr parport_pc parport soundcore 8250_fintek i2c_piix4 nfsd acpi_cpufreq auth_rpcgss nfs_acl lockd grace sunrpc uinput ext4 mbcache jbd2 cirrus syscopyarea sysfillrect sysimgblt drm_kms_helper virt
 io_blk ttm ata_generic pata_acpi drm 8139too ata_piix libata virtio_pci virtio_ring 8139cp i2c_core virtio mii floppy
[25044.422972] CPU: 0 PID: 5418 Comm: trinity-main Tainted: G    B           3.19.0-rc7-next-20150204+ #28
[25044.424649] Hardware name: Red Hat KVM, BIOS Bochs 01/01/2007
[25044.425889]  0000000000000000 00000000450cf6e2 ffff88007b90bca8 ffffffff8175d68e
[25044.427475]  0000000000000000 0000000000000000 ffff88007b90bce8 ffffffff8108930a
[25044.428739]  ffff88007b90bd08 ffff88007bc8d220 ffff880058fd0b70 ffffffff8183af80
[25044.430236] Call Trace:
[25044.430605]  [<ffffffff8175d68e>] dump_stack+0x4c/0x65
[25044.431548]  [<ffffffff8108930a>] warn_slowpath_common+0x8a/0xc0
[25044.432674]  [<ffffffff8108943a>] warn_slowpath_null+0x1a/0x20
[25044.433574]  [<ffffffff812af604>] locks_free_lock_context+0x64/0xc0
[25044.434821]  [<ffffffff8127139a>] __destroy_inode+0x3a/0x100
[25044.435761]  [<ffffffff81271486>] destroy_inode+0x26/0x70
[25044.436586]  [<ffffffff812715da>] evict+0x10a/0x180
[25044.437418]  [<ffffffff8127203e>] iput+0x1ce/0x390
[25044.438264]  [<ffffffff8126b320>] __dentry_kill+0x190/0x200
[25044.439310]  [<ffffffff8126c68e>] ? dput+0x26e/0x330
[25044.440411]  [<ffffffff8126c69d>] dput+0x27d/0x330
[25044.441173]  [<ffffffff8126c440>] ? dput+0x20/0x330
[25044.442248]  [<ffffffff81253417>] __fput+0x1a7/0x240
[25044.443138]  [<ffffffff812534fe>] ____fput+0xe/0x10
[25044.443880]  [<ffffffff810ae9fc>] task_work_run+0xbc/0xf0
[25044.444950]  [<ffffffff8108cbe9>] do_exit+0x389/0xcc0
[25044.445871]  [<ffffffff8115c384>] ? __audit_syscall_entry+0xb4/0x110
[25044.446956]  [<ffffffff8102d7cc>] ? do_audit_syscall_entry+0x6c/0x70
[25044.448171]  [<ffffffff8108d5bc>] do_group_exit+0x4c/0xc0
[25044.449171]  [<ffffffff8108d644>] SyS_exit_group+0x14/0x20
[25044.449991]  [<ffffffff817685ba>] tracesys_phase2+0xd8/0xdd
[25044.450808] ---[ end trace 840289003955b5ec ]---


Thanks,
--Shachar

^ permalink raw reply

* Re: Setting RPS affinities from network driver
From: Sunil Kovvuri @ 2015-02-18 15:47 UTC (permalink / raw)
  To: Tom Herbert; +Cc: Linux Netdev List, David S. Miller
In-Reply-To: <CA+mtBx9qHdEeXmEGbbWSr_OL3aAQJ37eTbC0mUY_XrTNoZ6iXw@mail.gmail.com>

Thanks Tom,

Will try to implement something like a library function which can be used
by any driver.

Regards,
Sunil.

On Wed, Feb 18, 2015 at 9:14 PM, Tom Herbert <therbert@google.com> wrote:
> On Tue, Feb 17, 2015 at 10:16 PM, Sunil Kovvuri <sunil.kovvuri@gmail.com> wrote:
>> Hi,
>>
>> I am writing a network driver for a multicore SOC with a on-board
>> network interface and would like to set RPS affinities from driver by
>> default. So that the network performance is good with whatever driver
>> supplied. Ofcourse these can be further adjusted from userspace
>> anyways.
>>
>> Is there a way to set RPS settings from driver itself ?
>> The only issue i am seeing is while setting 'rps_needed' key.
>>
> There is nothing to prevent this, but it would be really cool to make
> this into a library function that drivers can call to initialize RPS
> in some sane way (you might want to look at cpu_rmap).
>
>> static_key_slow_inc(&rps_needed);
>>
>> Currently this is not exported, so having issues while compiling
>> driver as module.
>>
>> If i export this symbol, will it be acceptable ?
>>
> Seems okay to me.
>
> Thanks,
> Tom
>
>>
>> Thanks,
>> Sunil.
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


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