Netdev List
 help / color / mirror / Atom feed
* [PATCH v2 net-next 2/4] udp: Move udp[46]_portaddr_hash() to net/ip[v6].h
From: Martin KaFai Lau @ 2017-12-01 20:52 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, Eric Dumazet, Kernel Team
In-Reply-To: <20171201205232.3012584-1-kafai@fb.com>

This patch moves the udp[46]_portaddr_hash()
to net/ip[v6].h.  The function name is renamed to
ipv[46]_portaddr_hash().

It will be used by a later patch which adds a second listener
hashtable hashed by the address and port.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
 include/net/ip.h   |  9 +++++++++
 include/net/ipv6.h | 17 +++++++++++++++++
 net/ipv4/udp.c     | 22 ++++++++--------------
 net/ipv6/udp.c     | 32 ++++++++------------------------
 4 files changed, 42 insertions(+), 38 deletions(-)

diff --git a/include/net/ip.h b/include/net/ip.h
index 9896f46cbbf1..fc9bf1b1fe2c 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -26,12 +26,14 @@
 #include <linux/ip.h>
 #include <linux/in.h>
 #include <linux/skbuff.h>
+#include <linux/jhash.h>
 
 #include <net/inet_sock.h>
 #include <net/route.h>
 #include <net/snmp.h>
 #include <net/flow.h>
 #include <net/flow_dissector.h>
+#include <net/netns/hash.h>
 
 #define IPV4_MAX_PMTU		65535U		/* RFC 2675, Section 5.1 */
 
@@ -521,6 +523,13 @@ static inline unsigned int ipv4_addr_hash(__be32 ip)
 	return (__force unsigned int) ip;
 }
 
+static inline u32 ipv4_portaddr_hash(const struct net *net,
+				     __be32 saddr,
+				     unsigned int port)
+{
+	return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port;
+}
+
 bool ip_call_ra_chain(struct sk_buff *skb);
 
 /*
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index f73797e2fa60..25be4715578c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -22,6 +22,7 @@
 #include <net/flow.h>
 #include <net/flow_dissector.h>
 #include <net/snmp.h>
+#include <net/netns/hash.h>
 
 #define SIN6_LEN_RFC2133	24
 
@@ -673,6 +674,22 @@ static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
 					cpu_to_be32(0x0000ffff))) == 0UL;
 }
 
+static inline u32 ipv6_portaddr_hash(const struct net *net,
+				     const struct in6_addr *addr6,
+				     unsigned int port)
+{
+	unsigned int hash, mix = net_hash_mix(net);
+
+	if (ipv6_addr_any(addr6))
+		hash = jhash_1word(0, mix);
+	else if (ipv6_addr_v4mapped(addr6))
+		hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix);
+	else
+		hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix);
+
+	return hash ^ port;
+}
+
 /*
  * Check for a RFC 4843 ORCHID address
  * (Overlay Routable Cryptographic Hash Identifiers)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 36f857c87fe2..e9c0d1e1772e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -357,18 +357,12 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 }
 EXPORT_SYMBOL(udp_lib_get_port);
 
-static u32 udp4_portaddr_hash(const struct net *net, __be32 saddr,
-			      unsigned int port)
-{
-	return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port;
-}
-
 int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
 	unsigned int hash2_nulladdr =
-		udp4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum);
+		ipv4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum);
 	unsigned int hash2_partial =
-		udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0);
+		ipv4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0);
 
 	/* precompute partial secondary hash */
 	udp_sk(sk)->udp_portaddr_hash = hash2_partial;
@@ -485,7 +479,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 	u32 hash = 0;
 
 	if (hslot->count > 10) {
-		hash2 = udp4_portaddr_hash(net, daddr, hnum);
+		hash2 = ipv4_portaddr_hash(net, daddr, hnum);
 		slot2 = hash2 & udptable->mask;
 		hslot2 = &udptable->hash2[slot2];
 		if (hslot->count < hslot2->count)
@@ -496,7 +490,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 					  exact_dif, hslot2, skb);
 		if (!result) {
 			unsigned int old_slot2 = slot2;
-			hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
+			hash2 = ipv4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
 			slot2 = hash2 & udptable->mask;
 			/* avoid searching the same slot again. */
 			if (unlikely(slot2 == old_slot2))
@@ -1761,7 +1755,7 @@ EXPORT_SYMBOL(udp_lib_rehash);
 
 static void udp_v4_rehash(struct sock *sk)
 {
-	u16 new_hash = udp4_portaddr_hash(sock_net(sk),
+	u16 new_hash = ipv4_portaddr_hash(sock_net(sk),
 					  inet_sk(sk)->inet_rcv_saddr,
 					  inet_sk(sk)->inet_num);
 	udp_lib_rehash(sk, new_hash);
@@ -1952,9 +1946,9 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	struct sk_buff *nskb;
 
 	if (use_hash2) {
-		hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
+		hash2_any = ipv4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
 			    udptable->mask;
-		hash2 = udp4_portaddr_hash(net, daddr, hnum) & udptable->mask;
+		hash2 = ipv4_portaddr_hash(net, daddr, hnum) & udptable->mask;
 start_lookup:
 		hslot = &udptable->hash2[hash2];
 		offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
@@ -2186,7 +2180,7 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net,
 					    int dif, int sdif)
 {
 	unsigned short hnum = ntohs(loc_port);
-	unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum);
+	unsigned int hash2 = ipv4_portaddr_hash(net, loc_addr, hnum);
 	unsigned int slot2 = hash2 & udp_table.mask;
 	struct udp_hslot *hslot2 = &udp_table.hash2[slot2];
 	INET_ADDR_COOKIE(acookie, rmt_addr, loc_addr);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c9f91c28b81d..eecf9f0faf29 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -89,28 +89,12 @@ static u32 udp6_ehashfn(const struct net *net,
 			       udp_ipv6_hash_secret + net_hash_mix(net));
 }
 
-static u32 udp6_portaddr_hash(const struct net *net,
-			      const struct in6_addr *addr6,
-			      unsigned int port)
-{
-	unsigned int hash, mix = net_hash_mix(net);
-
-	if (ipv6_addr_any(addr6))
-		hash = jhash_1word(0, mix);
-	else if (ipv6_addr_v4mapped(addr6))
-		hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix);
-	else
-		hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix);
-
-	return hash ^ port;
-}
-
 int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
 	unsigned int hash2_nulladdr =
-		udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum);
+		ipv6_portaddr_hash(sock_net(sk), &in6addr_any, snum);
 	unsigned int hash2_partial =
-		udp6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0);
+		ipv6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0);
 
 	/* precompute partial secondary hash */
 	udp_sk(sk)->udp_portaddr_hash = hash2_partial;
@@ -119,7 +103,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum)
 
 static void udp_v6_rehash(struct sock *sk)
 {
-	u16 new_hash = udp6_portaddr_hash(sock_net(sk),
+	u16 new_hash = ipv6_portaddr_hash(sock_net(sk),
 					  &sk->sk_v6_rcv_saddr,
 					  inet_sk(sk)->inet_num);
 
@@ -225,7 +209,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
 	u32 hash = 0;
 
 	if (hslot->count > 10) {
-		hash2 = udp6_portaddr_hash(net, daddr, hnum);
+		hash2 = ipv6_portaddr_hash(net, daddr, hnum);
 		slot2 = hash2 & udptable->mask;
 		hslot2 = &udptable->hash2[slot2];
 		if (hslot->count < hslot2->count)
@@ -236,7 +220,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
 					  hslot2, skb);
 		if (!result) {
 			unsigned int old_slot2 = slot2;
-			hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum);
+			hash2 = ipv6_portaddr_hash(net, &in6addr_any, hnum);
 			slot2 = hash2 & udptable->mask;
 			/* avoid searching the same slot again. */
 			if (unlikely(slot2 == old_slot2))
@@ -705,9 +689,9 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	struct sk_buff *nskb;
 
 	if (use_hash2) {
-		hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) &
+		hash2_any = ipv6_portaddr_hash(net, &in6addr_any, hnum) &
 			    udptable->mask;
-		hash2 = udp6_portaddr_hash(net, daddr, hnum) & udptable->mask;
+		hash2 = ipv6_portaddr_hash(net, daddr, hnum) & udptable->mask;
 start_lookup:
 		hslot = &udptable->hash2[hash2];
 		offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
@@ -895,7 +879,7 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net,
 			int dif, int sdif)
 {
 	unsigned short hnum = ntohs(loc_port);
-	unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum);
+	unsigned int hash2 = ipv6_portaddr_hash(net, loc_addr, hnum);
 	unsigned int slot2 = hash2 & udp_table.mask;
 	struct udp_hslot *hslot2 = &udp_table.hash2[slot2];
 	const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum);
-- 
2.9.5

^ permalink raw reply related

* [PATCH v2 net-next 0/4] tcp: Add a 2nd listener hashtable (port+addr)
From: Martin KaFai Lau @ 2017-12-01 20:52 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, Eric Dumazet, Kernel Team

This patch set adds a 2nd listener hashtable.  It is to resolve
the performance issue when a process is listening at many IP
addresses with the same port (e.g. [IP1]:443, [IP2]:443... [IPN]:443)

v2:
- Move the new lhash2 and lhash2_mask before the existing
  listening_hash to avoid adding another cacheline
  to inet_hashinfo (Suggested by Eric Dumazet, Thanks!)
- I take this chance to plug an existing 4 bytes hole while
  adding 'unsigned int lhash2_mask'.
- Add some comments about lhash2 in inet_hashtables.h

Martin KaFai Lau (4):
  inet: Add a count to struct inet_listen_hashbucket
  udp: Move udp[46]_portaddr_hash() to net/ip[v6].h
  inet: Add a 2nd listener hashtable (port+addr)
  tcp: Enable 2nd listener hashtable in TCP

 include/net/inet_connection_sock.h |   2 +
 include/net/inet_hashtables.h      |  29 +++++--
 include/net/ip.h                   |   9 ++
 include/net/ipv6.h                 |  17 ++++
 net/ipv4/inet_hashtables.c         | 173 +++++++++++++++++++++++++++++++++++--
 net/ipv4/tcp.c                     |   3 +
 net/ipv4/udp.c                     |  22 ++---
 net/ipv6/inet6_hashtables.c        |  66 ++++++++++++++
 net/ipv6/udp.c                     |  32 ++-----
 9 files changed, 301 insertions(+), 52 deletions(-)

-- 
2.9.5

^ permalink raw reply

* [PATCH v2 net-next 1/4] inet: Add a count to struct inet_listen_hashbucket
From: Martin KaFai Lau @ 2017-12-01 20:52 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, Eric Dumazet, Kernel Team
In-Reply-To: <20171201205232.3012584-1-kafai@fb.com>

This patch adds a count to the 'struct inet_listen_hashbucket'.
It counts how many sk is hashed to a bucket.  It will be
used to decide if the (to-be-added) portaddr listener's hashtable
should be used during inet[6]_lookup_listener().

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
 include/net/inet_hashtables.h |  1 +
 net/ipv4/inet_hashtables.c    | 11 +++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 2dbbbff5e1e3..4cce516c41ac 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -111,6 +111,7 @@ struct inet_bind_hashbucket {
  */
 struct inet_listen_hashbucket {
 	spinlock_t		lock;
+	unsigned int		count;
 	struct hlist_head	head;
 };
 
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 427b705d7c64..80cfd3fa21ca 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -476,6 +476,7 @@ int __inet_hash(struct sock *sk, struct sock *osk)
 		hlist_add_tail_rcu(&sk->sk_node, &ilb->head);
 	else
 		hlist_add_head_rcu(&sk->sk_node, &ilb->head);
+	ilb->count++;
 	sock_set_flag(sk, SOCK_RCU_FREE);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 unlock:
@@ -502,6 +503,7 @@ EXPORT_SYMBOL_GPL(inet_hash);
 void inet_unhash(struct sock *sk)
 {
 	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
+	struct inet_listen_hashbucket *ilb;
 	spinlock_t *lock;
 	bool listener = false;
 	int done;
@@ -510,7 +512,8 @@ void inet_unhash(struct sock *sk)
 		return;
 
 	if (sk->sk_state == TCP_LISTEN) {
-		lock = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)].lock;
+		ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
+		lock = &ilb->lock;
 		listener = true;
 	} else {
 		lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
@@ -522,8 +525,11 @@ void inet_unhash(struct sock *sk)
 		done = __sk_del_node_init(sk);
 	else
 		done = __sk_nulls_del_node_init_rcu(sk);
-	if (done)
+	if (done) {
+		if (listener)
+			ilb->count--;
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	}
 	spin_unlock_bh(lock);
 }
 EXPORT_SYMBOL_GPL(inet_unhash);
@@ -658,6 +664,7 @@ void inet_hashinfo_init(struct inet_hashinfo *h)
 	for (i = 0; i < INET_LHTABLE_SIZE; i++) {
 		spin_lock_init(&h->listening_hash[i].lock);
 		INIT_HLIST_HEAD(&h->listening_hash[i].head);
+		h->listening_hash[i].count = 0;
 	}
 }
 EXPORT_SYMBOL_GPL(inet_hashinfo_init);
-- 
2.9.5

^ permalink raw reply related

* [PATCH v2 net-next 3/4] inet: Add a 2nd listener hashtable (port+addr)
From: Martin KaFai Lau @ 2017-12-01 20:52 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, Eric Dumazet, Kernel Team
In-Reply-To: <20171201205232.3012584-1-kafai@fb.com>

The current listener hashtable is hashed by port only.
When a process is listening at many IP addresses with the same port (e.g.
[IP1]:443, [IP2]:443... [IPN]:443), the inet[6]_lookup_listener()
performance is degraded to a link list.  It is prone to syn attack.

UDP had a similar issue and a second hashtable was added to resolve it.

This patch adds a second hashtable for the listener's sockets.
The second hashtable is hashed by port and address.

It cannot reuse the existing skc_portaddr_node which is shared
with skc_bind_node.  TCP listener needs to use skc_bind_node.
Instead, this patch adds a hlist_node 'icsk_listen_portaddr_node' to
the inet_connection_sock which the listener (like TCP) also belongs to.

The new portaddr hashtable may need two lookup (First by IP:PORT.
Second by INADDR_ANY:PORT if the IP:PORT is a not found).   Hence,
it implements a similar cut off as UDP such that it will only consult the
new portaddr hashtable if the current port-only hashtable has >10
sk in the link-list.

lhash2 and lhash2_mask are added to 'struct inet_hashinfo'.  I take
this chance to plug a 4 bytes hole.  It is done by first moving
the existing bind_bucket_cachep up and then add the new
(int lhash2_mask, *lhash2) after the existing bhash_size.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
---
 include/net/inet_connection_sock.h |   2 +
 include/net/inet_hashtables.h      |  28 +++++--
 net/ipv4/inet_hashtables.c         | 168 +++++++++++++++++++++++++++++++++++--
 net/ipv6/inet6_hashtables.c        |  66 +++++++++++++++
 4 files changed, 249 insertions(+), 15 deletions(-)

diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 0358745ea059..8e1bf9ae4a5e 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -77,6 +77,7 @@ struct inet_connection_sock_af_ops {
  * @icsk_af_ops		   Operations which are AF_INET{4,6} specific
  * @icsk_ulp_ops	   Pluggable ULP control hook
  * @icsk_ulp_data	   ULP private data
+ * @icsk_listen_portaddr_node	hash to the portaddr listener hashtable
  * @icsk_ca_state:	   Congestion control state
  * @icsk_retransmits:	   Number of unrecovered [RTO] timeouts
  * @icsk_pending:	   Scheduled timer event
@@ -101,6 +102,7 @@ struct inet_connection_sock {
 	const struct inet_connection_sock_af_ops *icsk_af_ops;
 	const struct tcp_ulp_ops  *icsk_ulp_ops;
 	void			  *icsk_ulp_data;
+	struct hlist_node         icsk_listen_portaddr_node;
 	unsigned int		  (*icsk_sync_mss)(struct sock *sk, u32 pmtu);
 	__u8			  icsk_ca_state:6,
 				  icsk_ca_setsockopt:1,
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 4cce516c41ac..9141e95529e7 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -133,12 +133,13 @@ struct inet_hashinfo {
 	/* Ok, let's try this, I give up, we do need a local binding
 	 * TCP hash as well as the others for fast bind/connect.
 	 */
+	struct kmem_cache		*bind_bucket_cachep;
 	struct inet_bind_hashbucket	*bhash;
-
 	unsigned int			bhash_size;
-	/* 4 bytes hole on 64 bit */
 
-	struct kmem_cache		*bind_bucket_cachep;
+	/* The 2nd listener table hashed by local port and address */
+	unsigned int			lhash2_mask;
+	struct inet_listen_hashbucket	*lhash2;
 
 	/* All the above members are written once at bootup and
 	 * never written again _or_ are predominantly read-access.
@@ -146,14 +147,25 @@ struct inet_hashinfo {
 	 * Now align to a new cache line as all the following members
 	 * might be often dirty.
 	 */
-	/* All sockets in TCP_LISTEN state will be in here.  This is the only
-	 * table where wildcard'd TCP sockets can exist.  Hash function here
-	 * is just local port number.
+	/* All sockets in TCP_LISTEN state will be in listening_hash.
+	 * This is the only table where wildcard'd TCP sockets can
+	 * exist.  listening_hash is only hashed by local port number.
+	 * If lhash2 is initialized, the same socket will also be hashed
+	 * to lhash2 by port and address.
 	 */
 	struct inet_listen_hashbucket	listening_hash[INET_LHTABLE_SIZE]
 					____cacheline_aligned_in_smp;
 };
 
+#define inet_lhash2_for_each_icsk_rcu(__icsk, list) \
+	hlist_for_each_entry_rcu(__icsk, list, icsk_listen_portaddr_node)
+
+static inline struct inet_listen_hashbucket *
+inet_lhash2_bucket(struct inet_hashinfo *h, u32 hash)
+{
+	return &h->lhash2[hash & h->lhash2_mask];
+}
+
 static inline struct inet_ehash_bucket *inet_ehash_bucket(
 	struct inet_hashinfo *hashinfo,
 	unsigned int hash)
@@ -209,6 +221,10 @@ int __inet_inherit_port(const struct sock *sk, struct sock *child);
 void inet_put_port(struct sock *sk);
 
 void inet_hashinfo_init(struct inet_hashinfo *h);
+void inet_hashinfo2_init(struct inet_hashinfo *h, const char *name,
+			 unsigned long numentries, int scale,
+			 unsigned long low_limit,
+			 unsigned long high_limit);
 
 bool inet_ehash_insert(struct sock *sk, struct sock *osk);
 bool inet_ehash_nolisten(struct sock *sk, struct sock *osk);
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 80cfd3fa21ca..f6f58108b4c5 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
+#include <linux/bootmem.h>
 
 #include <net/addrconf.h>
 #include <net/inet_connection_sock.h>
@@ -168,6 +169,60 @@ int __inet_inherit_port(const struct sock *sk, struct sock *child)
 }
 EXPORT_SYMBOL_GPL(__inet_inherit_port);
 
+static struct inet_listen_hashbucket *
+inet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk)
+{
+	u32 hash;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	if (sk->sk_family == AF_INET6)
+		hash = ipv6_portaddr_hash(sock_net(sk),
+					  &sk->sk_v6_rcv_saddr,
+					  inet_sk(sk)->inet_num);
+	else
+#endif
+		hash = ipv4_portaddr_hash(sock_net(sk),
+					  inet_sk(sk)->inet_rcv_saddr,
+					  inet_sk(sk)->inet_num);
+	return inet_lhash2_bucket(h, hash);
+}
+
+static void inet_hash2(struct inet_hashinfo *h, struct sock *sk)
+{
+	struct inet_listen_hashbucket *ilb2;
+
+	if (!h->lhash2)
+		return;
+
+	ilb2 = inet_lhash2_bucket_sk(h, sk);
+
+	spin_lock(&ilb2->lock);
+	if (sk->sk_reuseport && sk->sk_family == AF_INET6)
+		hlist_add_tail_rcu(&inet_csk(sk)->icsk_listen_portaddr_node,
+				   &ilb2->head);
+	else
+		hlist_add_head_rcu(&inet_csk(sk)->icsk_listen_portaddr_node,
+				   &ilb2->head);
+	ilb2->count++;
+	spin_unlock(&ilb2->lock);
+}
+
+static void inet_unhash2(struct inet_hashinfo *h, struct sock *sk)
+{
+	struct inet_listen_hashbucket *ilb2;
+
+	if (!h->lhash2 ||
+	    WARN_ON_ONCE(hlist_unhashed(&inet_csk(sk)->icsk_listen_portaddr_node)))
+		return;
+
+	ilb2 = inet_lhash2_bucket_sk(h, sk);
+
+	spin_lock(&ilb2->lock);
+	hlist_del_init_rcu(&inet_csk(sk)->icsk_listen_portaddr_node);
+	ilb2->count--;
+	spin_unlock(&ilb2->lock);
+}
+
 static inline int compute_score(struct sock *sk, struct net *net,
 				const unsigned short hnum, const __be32 daddr,
 				const int dif, const int sdif, bool exact_dif)
@@ -207,6 +262,40 @@ static inline int compute_score(struct sock *sk, struct net *net,
  */
 
 /* called with rcu_read_lock() : No refcount taken on the socket */
+static struct sock *inet_lhash2_lookup(struct net *net,
+				struct inet_listen_hashbucket *ilb2,
+				struct sk_buff *skb, int doff,
+				const __be32 saddr, __be16 sport,
+				const __be32 daddr, const unsigned short hnum,
+				const int dif, const int sdif)
+{
+	bool exact_dif = inet_exact_dif_match(net, skb);
+	struct inet_connection_sock *icsk;
+	struct sock *sk, *result = NULL;
+	int score, hiscore = 0;
+	u32 phash = 0;
+
+	inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) {
+		sk = (struct sock *)icsk;
+		score = compute_score(sk, net, hnum, daddr,
+				      dif, sdif, exact_dif);
+		if (score > hiscore) {
+			if (sk->sk_reuseport) {
+				phash = inet_ehashfn(net, daddr, hnum,
+						     saddr, sport);
+				result = reuseport_select_sock(sk, phash,
+							       skb, doff);
+				if (result)
+					return result;
+			}
+			result = sk;
+			hiscore = score;
+		}
+	}
+
+	return result;
+}
+
 struct sock *__inet_lookup_listener(struct net *net,
 				    struct inet_hashinfo *hashinfo,
 				    struct sk_buff *skb, int doff,
@@ -217,10 +306,42 @@ struct sock *__inet_lookup_listener(struct net *net,
 	unsigned int hash = inet_lhashfn(net, hnum);
 	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 	bool exact_dif = inet_exact_dif_match(net, skb);
+	struct inet_listen_hashbucket *ilb2;
 	struct sock *sk, *result = NULL;
 	int score, hiscore = 0;
+	unsigned int hash2;
 	u32 phash = 0;
 
+	if (ilb->count <= 10 || !hashinfo->lhash2)
+		goto port_lookup;
+
+	/* Too many sk in the ilb bucket (which is hashed by port alone).
+	 * Try lhash2 (which is hashed by port and addr) instead.
+	 */
+
+	hash2 = ipv4_portaddr_hash(net, daddr, hnum);
+	ilb2 = inet_lhash2_bucket(hashinfo, hash2);
+	if (ilb2->count > ilb->count)
+		goto port_lookup;
+
+	result = inet_lhash2_lookup(net, ilb2, skb, doff,
+				    saddr, sport, daddr, hnum,
+				    dif, sdif);
+	if (result)
+		return result;
+
+	/* Lookup lhash2 with INADDR_ANY */
+
+	hash2 = ipv4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
+	ilb2 = inet_lhash2_bucket(hashinfo, hash2);
+	if (ilb2->count > ilb->count)
+		goto port_lookup;
+
+	return inet_lhash2_lookup(net, ilb2, skb, doff,
+				  saddr, sport, daddr, hnum,
+				  dif, sdif);
+
+port_lookup:
 	sk_for_each_rcu(sk, &ilb->head) {
 		score = compute_score(sk, net, hnum, daddr,
 				      dif, sdif, exact_dif);
@@ -476,6 +597,7 @@ int __inet_hash(struct sock *sk, struct sock *osk)
 		hlist_add_tail_rcu(&sk->sk_node, &ilb->head);
 	else
 		hlist_add_head_rcu(&sk->sk_node, &ilb->head);
+	inet_hash2(hashinfo, sk);
 	ilb->count++;
 	sock_set_flag(sk, SOCK_RCU_FREE);
 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -506,7 +628,6 @@ void inet_unhash(struct sock *sk)
 	struct inet_listen_hashbucket *ilb;
 	spinlock_t *lock;
 	bool listener = false;
-	int done;
 
 	if (sk_unhashed(sk))
 		return;
@@ -519,17 +640,20 @@ void inet_unhash(struct sock *sk)
 		lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
 	}
 	spin_lock_bh(lock);
+	if (sk_unhashed(sk))
+		goto unlock;
+
 	if (rcu_access_pointer(sk->sk_reuseport_cb))
 		reuseport_detach_sock(sk);
-	if (listener)
-		done = __sk_del_node_init(sk);
-	else
-		done = __sk_nulls_del_node_init_rcu(sk);
-	if (done) {
-		if (listener)
-			ilb->count--;
-		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	if (listener) {
+		inet_unhash2(hashinfo, sk);
+		 __sk_del_node_init(sk);
+		 ilb->count--;
+	} else {
+		__sk_nulls_del_node_init_rcu(sk);
 	}
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+unlock:
 	spin_unlock_bh(lock);
 }
 EXPORT_SYMBOL_GPL(inet_unhash);
@@ -666,9 +790,35 @@ void inet_hashinfo_init(struct inet_hashinfo *h)
 		INIT_HLIST_HEAD(&h->listening_hash[i].head);
 		h->listening_hash[i].count = 0;
 	}
+
+	h->lhash2 = NULL;
 }
 EXPORT_SYMBOL_GPL(inet_hashinfo_init);
 
+void __init inet_hashinfo2_init(struct inet_hashinfo *h, const char *name,
+				unsigned long numentries, int scale,
+				unsigned long low_limit,
+				unsigned long high_limit)
+{
+	unsigned int i;
+
+	h->lhash2 = alloc_large_system_hash(name,
+					    sizeof(*h->lhash2),
+					    numentries,
+					    scale,
+					    0,
+					    NULL,
+					    &h->lhash2_mask,
+					    low_limit,
+					    high_limit);
+
+	for (i = 0; i <= h->lhash2_mask; i++) {
+		spin_lock_init(&h->lhash2[i].lock);
+		INIT_HLIST_HEAD(&h->lhash2[i].head);
+		h->lhash2[i].count = 0;
+	}
+}
+
 int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo)
 {
 	unsigned int locksz = sizeof(spinlock_t);
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 0d1451381f5c..2febe26de6a1 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -125,6 +125,40 @@ static inline int compute_score(struct sock *sk, struct net *net,
 }
 
 /* called with rcu_read_lock() */
+static struct sock *inet6_lhash2_lookup(struct net *net,
+		struct inet_listen_hashbucket *ilb2,
+		struct sk_buff *skb, int doff,
+		const struct in6_addr *saddr,
+		const __be16 sport, const struct in6_addr *daddr,
+		const unsigned short hnum, const int dif, const int sdif)
+{
+	bool exact_dif = inet6_exact_dif_match(net, skb);
+	struct inet_connection_sock *icsk;
+	struct sock *sk, *result = NULL;
+	int score, hiscore = 0;
+	u32 phash = 0;
+
+	inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) {
+		sk = (struct sock *)icsk;
+		score = compute_score(sk, net, hnum, daddr, dif, sdif,
+				      exact_dif);
+		if (score > hiscore) {
+			if (sk->sk_reuseport) {
+				phash = inet6_ehashfn(net, daddr, hnum,
+						      saddr, sport);
+				result = reuseport_select_sock(sk, phash,
+							       skb, doff);
+				if (result)
+					return result;
+			}
+			result = sk;
+			hiscore = score;
+		}
+	}
+
+	return result;
+}
+
 struct sock *inet6_lookup_listener(struct net *net,
 		struct inet_hashinfo *hashinfo,
 		struct sk_buff *skb, int doff,
@@ -135,10 +169,42 @@ struct sock *inet6_lookup_listener(struct net *net,
 	unsigned int hash = inet_lhashfn(net, hnum);
 	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 	bool exact_dif = inet6_exact_dif_match(net, skb);
+	struct inet_listen_hashbucket *ilb2;
 	struct sock *sk, *result = NULL;
 	int score, hiscore = 0;
+	unsigned int hash2;
 	u32 phash = 0;
 
+	if (ilb->count <= 10 || !hashinfo->lhash2)
+		goto port_lookup;
+
+	/* Too many sk in the ilb bucket (which is hashed by port alone).
+	 * Try lhash2 (which is hashed by port and addr) instead.
+	 */
+
+	hash2 = ipv6_portaddr_hash(net, daddr, hnum);
+	ilb2 = inet_lhash2_bucket(hashinfo, hash2);
+	if (ilb2->count > ilb->count)
+		goto port_lookup;
+
+	result = inet6_lhash2_lookup(net, ilb2, skb, doff,
+				     saddr, sport, daddr, hnum,
+				     dif, sdif);
+	if (result)
+		return result;
+
+	/* Lookup lhash2 with in6addr_any */
+
+	hash2 = ipv6_portaddr_hash(net, &in6addr_any, hnum);
+	ilb2 = inet_lhash2_bucket(hashinfo, hash2);
+	if (ilb2->count > ilb->count)
+		goto port_lookup;
+
+	return inet6_lhash2_lookup(net, ilb2, skb, doff,
+				   saddr, sport, daddr, hnum,
+				   dif, sdif);
+
+port_lookup:
 	sk_for_each(sk, &ilb->head) {
 		score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif);
 		if (score > hiscore) {
-- 
2.9.5

^ permalink raw reply related

* [PATCH v2 net-next 4/4] tcp: Enable 2nd listener hashtable in TCP
From: Martin KaFai Lau @ 2017-12-01 20:52 UTC (permalink / raw)
  To: netdev; +Cc: David S . Miller, Eric Dumazet, Kernel Team
In-Reply-To: <20171201205232.3012584-1-kafai@fb.com>

Enable the second listener hashtable in TCP.
The scale is the same as UDP which is one slot per 2MB.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
 net/ipv4/tcp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index bf97317e6c97..180311636023 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3577,6 +3577,9 @@ void __init tcp_init(void)
 	percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL);
 	percpu_counter_init(&tcp_orphan_count, 0, GFP_KERNEL);
 	inet_hashinfo_init(&tcp_hashinfo);
+	inet_hashinfo2_init(&tcp_hashinfo, "tcp_listen_portaddr_hash",
+			    thash_entries, 21,  /* one slot per 2 MB*/
+			    0, 64 * 1024);
 	tcp_hashinfo.bind_bucket_cachep =
 		kmem_cache_create("tcp_bind_bucket",
 				  sizeof(struct inet_bind_bucket), 0,
-- 
2.9.5

^ permalink raw reply related

* Re: [PATCH net] tcp/dccp: block bh before arming time_wait timer
From: Eric Dumazet @ 2017-12-01 20:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, maze
In-Reply-To: <20171201.151244.214660651517525372.davem@davemloft.net>

On Fri, 2017-12-01 at 15:12 -0500, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 01 Dec 2017 10:06:56 -0800
> 
> > From: Eric Dumazet <edumazet@google.com>
> > 
> > Maciej Żenczykowski reported some panics in tcp_twsk_destructor()
> > that might be caused by the following bug.
> > 
> > timewait timer is pinned to the cpu, because we want to transition
> > timwewait refcount from 0 to 4 in one go, once everything has been
> > initialized.
> > 
> > At the time commit ed2e92394589 ("tcp/dccp: fix timewait races in
> timer
> > handling") was merged, TCP was always running from BH habdler.
> > 
> > After commit 5413d1babe8f ("net: do not block BH while processing
> > socket backlog") we definitely can run tcp_time_wait() from process
> > context.
> > 
> > We need to block BH in the critical section so that the pinned
> timer
> > has still its purpose.
> > 
> > This bug is more likely to happen under stress and when very small
> RTO
> > are used in datacenter flows.
> > 
> > Fixes: 5413d1babe8f ("net: do not block BH while processing socket
> backlog")
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> > Reported-by: Maciej Żenczykowski <maze@google.com>
> 
> Applied and queued up for -stable, thanks Eric.

It just occurred to me that we can now revert 614bdd4d6e61d26
("tcp: must block bh in __inet_twsk_hashdance()")

^ permalink raw reply

* Re: netfilter: xt_bpf: Fix XT_BPF_MODE_FD_PINNED mode of 'xt_bpf_info_v1'
From: Daniel Borkmann @ 2017-12-01 20:47 UTC (permalink / raw)
  To: Al Viro, Kees Cook
  Cc: Shmulik Ladkani, Willem de Bruijn, Pablo Neira Ayuso,
	Linus Torvalds, David Miller, LKML, Network Development,
	Christoph Hellwig, Thomas Garnier, Jann Horn
In-Reply-To: <20171201173941.GP21978@ZenIV.linux.org.uk>

On 12/01/2017 06:39 PM, Al Viro wrote:
[...]
> If that does not scream "wrong or missing primitive", I don't know what would.
> You want something along the lines of "create a filesystem object at given
> location, calling this function with this argument for actual object creation"?
> Fair enough, but then let's add a primitive that would do just that.
> 
> And grepping around for similar sick tricks catches a slightly milder example -
> mq_open(2) doesn't play with encoding stuff into dev_t, but otherwise it's very
> similar and could also benefit from the same primitive.
> 
> How about something like this:
> int vfs_mkobj(struct dentry *dentry, umode_t mode,
>                 int (*f)(struct dentry *, umode_t, void *),
> 		void *arg)
> {
> 	struct inode *dir = dentry->d_parent->d_inode;
>         int error = may_create(dir, dentry);
>         if (error)
>                 return error;
> 
>         mode &= S_IALLUGO;
>         mode |= S_IFREG;
>         error = security_inode_create(dir, dentry, mode);
>         if (error)
>                 return error;
>         error = f(dentry, mode, arg);
>         if (!error)
>                 fsnotify_create(dir, dentry);
>         return error;
> }
> 
> exported by fs/namei.c, with your code doing
> 
> 	switch (type) {
> 	case BPF_TYPE_PROG:
> 		error = vfs_mkobj(path.dentry, mode, bpf_mkprog, raw);
> 		break;
> 	case BPF_TYPE_MAP:
> 		error = vfs_mkobj(path.dentry, mode, bpf_mkmap, raw);
> 		break;
> 	default:
> 		error = -EPERM;
> 	}
> instead that vfs_mknod() hack, with
> 
> static int bpf_mkprog(struct inode *dir, struct dentry *dentry,
> 		 umode_t mode, void *raw)
> {
> 	return bpf_mkobj_ops(dir, dentry, mode, raw, &bpf_prog_iops);
> }
> 
> static int bpf_mkmap(struct inode *dir, struct dentry *dentry,
> 		 umode_t mode, void *raw)
> {
> 	return bpf_mkobj_ops(dir, dentry, mode, raw, &bpf_map_iops);
> }
> 
> static int bpf_mkobj_ops(struct inode *dir, struct dentry *dentry,
> 		 umode_t mode, void *raw, struct inode_operations *iops)
> {
>         struct inode *inode;
> 
>         inode = bpf_get_inode(dir->i_sb, dir, mode);
>         if (IS_ERR(inode))
>                 return PTR_ERR(inode);
> 
>         inode->i_op = iops;
>         inode->i_private = raw;
> 
>         bpf_dentry_finalize(dentry, inode, dir);
>         return 0;
> }
> 
> And to hell with messing with dev_t, ->d_fsdata or having ->mknod() there at all...
> Might want to replace security_path_mknod() with something saner, while we are
> at it.
> 
> Objections?

No, thanks for looking into this, and sorry for this fugly hack! :( Not
that this doesn't make it any better, but I think back then I took it
over from mqueue implementation ... should have known better and looking
into making this generic instead, sigh. The above looks good to me, so
no objections from my side and thanks for working on it!

> PS: mqueue.c would also benefit from such primitive - do_create() there would
> simply pass attr as callback's argument into vfs_mkobj(), with callback being
> the guts of mqueue_create()...

^ permalink raw reply

* Re: [PATCH net-next resubmit 2/2] net: phy: remove generic settings for callbacks config_aneg and read_status from drivers
From: David Miller @ 2017-12-01 20:42 UTC (permalink / raw)
  To: hkallweit1; +Cc: f.fainelli, andrew, netdev
In-Reply-To: <9656694a-0113-6090-b1fd-58fdb05b8977@gmail.com>

From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Thu, 30 Nov 2017 23:47:52 +0100

> Remove generic settings for callbacks config_aneg and read_status
> from drivers.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH net-next resubmit 1/2] net: phy: core: use genphy version of callbacks read_status and config_aneg per default
From: David Miller @ 2017-12-01 20:42 UTC (permalink / raw)
  To: hkallweit1; +Cc: f.fainelli, andrew, netdev
In-Reply-To: <e9350088-76f9-be2c-e2ac-b3860d96e095@gmail.com>

From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Thu, 30 Nov 2017 23:46:19 +0100

> read_status and config_aneg are the only mandatory callbacks and most
> of the time the generic implementation is used by drivers.
> So make the core fall back to the generic version if a driver doesn't
> implement the respective callback.
> 
> Also currently the core doesn't seem to verify that drivers implement
> the mandatory calls. If a driver doesn't do so we'd just get a NPE.
> With this patch this potential issue doesn't exit any longer.
> 
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
From: Philippe Ombredanne @ 2017-12-01 20:41 UTC (permalink / raw)
  To: David Daney
  Cc: Greg Kroah-Hartman, Carlos Munoz, David Daney, linux-mips, ralf,
	netdev, David S. Miller, Rob Herring, Mark Rutland, devel, LKML,
	Steven J. Hill,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Andrew Lunn, Florian Fainelli, James Hogan
In-Reply-To: <2ac5ec17-cedb-5dd8-6ea7-f065025639a9@caviumnetworks.com>

David,

On Fri, Dec 1, 2017 at 9:01 PM, David Daney <ddaney@caviumnetworks.com> wrote:
> On 12/01/2017 11:49 AM, Philippe Ombredanne wrote:
>>
>> David, Greg,
>>
>> On Fri, Dec 1, 2017 at 6:42 PM, David Daney <ddaney@caviumnetworks.com>
>> wrote:
>>>
>>> On 11/30/2017 11:53 PM, Philippe Ombredanne wrote:
>>
>> [...]
>>>>>>
>>>>>> --- /dev/null
>>>>>> +++ b/arch/mips/cavium-octeon/resource-mgr.c
>>>>>> @@ -0,0 +1,371 @@
>>>>>> +// SPDX-License-Identifier: GPL-2.0
>>>>>> +/*
>>>>>> + * Resource manager for Octeon.
>>>>>> + *
>>>>>> + * This file is subject to the terms and conditions of the GNU
>>>>>> General
>>>>>> Public
>>>>>> + * License.  See the file "COPYING" in the main directory of this
>>>>>> archive
>>>>>> + * for more details.
>>>>>> + *
>>>>>> + * Copyright (C) 2017 Cavium, Inc.
>>>>>> + */
>>>>
>>>>
>>>>
>>>> Since you nicely included an SPDX id, you would not need the
>>>> boilerplate anymore. e.g. these can go alright?
>>>
>>>
>>>
>>> They may not be strictly speaking necessary, but I don't think they hurt
>>> anything.  Unless there is a requirement to strip out the license text,
>>> we
>>> would stick with it as is.
>>
>>
>> I think the requirement is there and that would be much better for
>> everyone: keeping both is redundant and does not bring any value, does
>> it? Instead it kinda removes the benefits of having the SPDX id in the
>> first place IMHO.
>>
>> Furthermore, as there have been already ~12K+ files cleaned up and
>> still over 60K files to go, it would really nice if new files could
>> adopt the new style: this way we will not have to revisit and repatch
>> them in the future.
>>
>
> I am happy to follow any style Greg would suggest.  There doesn't seem to be
> much documentation about how this should be done yet.

Thomas (tglx) has already submitted a first series of doc patches a
few weeks ago. And AFAIK he might be working on posting the updates
soon, whenever his real time clock yields a few cycles away from real
time coding work ;)

See also these discussions with Linus [1][2][3], Thomas[4] and Greg[5]
on this and mostly related topics

[1] https://lkml.org/lkml/2017/11/2/715
[2] https://lkml.org/lkml/2017/11/25/125
[3] https://lkml.org/lkml/2017/11/25/133
[4] https://lkml.org/lkml/2017/11/2/805
[5] https://lkml.org/lkml/2017/10/19/165

-- 
Cordially
Philippe Ombredanne

^ permalink raw reply

* Re: [PATCH v5 net-next 0/3] ip6_gre: add erspan native tunnel for ipv6
From: David Miller @ 2017-12-01 20:37 UTC (permalink / raw)
  To: u9012063; +Cc: netdev
In-Reply-To: <1512071489-5318-1-git-send-email-u9012063@gmail.com>

From: William Tu <u9012063@gmail.com>
Date: Thu, 30 Nov 2017 11:51:26 -0800

> The patch series add support for ERSPAN tunnel over ipv6.  The first patch
> refectors the existing ipv4 gre implementation and the second refactors the
> ipv6 gre's xmit code.  Finally the last patch introduces erspan protocol.

Series applied, thanks William.

^ permalink raw reply

* Re: [PATCH RFC 2/2] veth: propagate bridge GSO to peer
From: Stephen Hemminger @ 2017-12-01 20:30 UTC (permalink / raw)
  To: David Ahern; +Cc: Solio Sarabia, davem, netdev, sthemmin
In-Reply-To: <91628267-2e48-a231-7cc2-4830eb95ceef@gmail.com>

On Mon, 27 Nov 2017 19:02:01 -0700
David Ahern <dsahern@gmail.com> wrote:

> On 11/27/17 6:42 PM, Solio Sarabia wrote:
> > On Mon, Nov 27, 2017 at 01:15:02PM -0800, Stephen Hemminger wrote:  
> >> On Mon, 27 Nov 2017 12:14:19 -0800
> >> Solio Sarabia <solio.sarabia@intel.com> wrote:
> >>  
> >>> On Sun, Nov 26, 2017 at 11:07:25PM -0800, Stephen Hemminger wrote:  
> >>>> On Sun, 26 Nov 2017 20:13:39 -0700
> >>>> David Ahern <dsahern@gmail.com> wrote:
> >>>>     
> >>>>> On 11/26/17 11:17 AM, Stephen Hemminger wrote:    
> >>>>>> This allows veth device in containers to see the GSO maximum
> >>>>>> settings of the actual device being used for output.    
> >>>>>
> >>>>> veth devices can be added to a VRF instead of a bridge, and I do not
> >>>>> believe the gso propagation works for L3 master devices.
> >>>>>
> >>>>> From a quick grep, team devices do not appear to handle gso changes either.    
> >>>>
> >>>> This code should still work correctly, but no optimization would happen.
> >>>> The gso_max_size of the VRF or team will
> >>>> still be GSO_MAX_SIZE so there would be no change. If VRF or Team ever got smart
> >>>> enough to handle GSO limits, then the algorithm would handle it.    
> >>>
> >>> This patch propagates gso value from bridge to its veth endpoints.
> >>> However, since bridge is never aware of the GSO limit from underlying
> >>> interfaces, bridge/veth still have larger GSO size.
> >>>
> >>> In the docker case, bridge is not linked directly to physical or
> >>> synthetic interfaces; it relies on iptables to decide which interface to
> >>> forward packets to.  
> >>
> >> So for the docker case, then direct control of GSO values via netlink (ie ip link set)
> >> seems like the better solution.  
> > 
> > Adding ioctl support for 'ip link set' would work. I'm still concerned
> > how to enforce the upper limit to not exceed that of the lower devices.
> > 
> > Consider a system with three NICs, each reporting values in the range
> > [60,000 - 62,780]. Users could set virtual interfaces' gso to 65,536,
> > exceeding the limit, and having the host do sw gso (vms settings must
> > not affect host performance.)
> > 
> > Looping through interfaces?  With the difference that now it'd be
> > trigger upon user's request, not every time a veth is created (like one
> > previous patch discussed.)
> >   
> 
> You are concerned about the routed case right? One option is to have VRF
> devices propagate gso sizes to all devices (veth, vlan, etc) enslaved to
> it. VRF devices are Layer 3 master devices so an L3 parallel to a bridge.

See the patch set I posted today which punts the problem to veth setup.

^ permalink raw reply

* Re: [PATCH 0/2] net: ethtool: add support for ETH_RESET_AP
From: David Miller @ 2017-12-01 20:30 UTC (permalink / raw)
  To: scott.branden
  Cc: allan.nielsen, andrew, Raju.Lakkaraju, f.fainelli,
	bcm-kernel-feedback-list, linux-kernel, steven.lin1, netdev,
	michael.chan
In-Reply-To: <1512070560-16739-1-git-send-email-scott.branden@broadcom.com>

From: Scott Branden <scott.branden@broadcom.com>
Date: Thu, 30 Nov 2017 11:35:58 -0800

> Add support to reset appplication processors inside SmartNICs by
> defining new ETH_RESET_AP bit.
> 
> And use new ETH_RESET_AP bit in bnxt ethernet driver.

Looks good, series applied, thanks!

^ permalink raw reply

* Re: [PATCH net-next 0/3] rds-tcp netns delete related fixes
From: David Miller @ 2017-12-01 20:25 UTC (permalink / raw)
  To: sowmini.varadhan; +Cc: netdev, rds-devel, santosh.shilimkar
In-Reply-To: <cover.1511195030.git.sowmini.varadhan@oracle.com>

From: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Date: Thu, 30 Nov 2017 11:11:26 -0800

> Patchset contains cleanup and bug fixes. Patch 1 is the removal
> of some redundant code/functions. Patch 2 and 3 are fixes for 
> corner cases identified by syzkaller. I've not been able to
> reproduce the actual use-after-free race flagged in the syzkaller
> reports, thus these fixes are based on code inspection plus 
> manual testing to make sure the modified code paths are executed 
> without problems in the commonly encountered timing cases.

Series applied, thanks.

^ permalink raw reply

* Re: [net-next 1/1] tipc: fall back to smaller MTU if allocation of local send skb fails
From: David Miller @ 2017-12-01 20:22 UTC (permalink / raw)
  To: jon.maloy
  Cc: netdev, mohan.krishna.ghanta.krishnamurthy, tung.q.nguyen,
	hoang.h.le, canh.d.luu, ying.xue, tipc-discussion
In-Reply-To: <1512056845-2284-1-git-send-email-jon.maloy@ericsson.com>

From: Jon Maloy <jon.maloy@ericsson.com>
Date: Thu, 30 Nov 2017 16:47:25 +0100

> When sending node local messages the code is using an 'mtu' of 66060
> bytes to avoid unnecessary fragmentation. During situations of low
> memory tipc_msg_build() may sometimes fail to allocate such large
> buffers, resulting in unnecessary send failures. This can easily be
> remedied by falling back to a smaller MTU, and then reassemble the
> buffer chain as if the message were arriving from a remote node.
> 
> At the same time, we change the initial MTU setting of the broadcast
> link to a lower value, so that large messages always are fragmented
> into smaller buffers even when we run in single node mode. Apart from
> obtaining the same advantage as for the 'fallback' solution above, this
> turns out to give a significant performance improvement. This can
> probably be explained with the __pskb_copy() operation performed on the
> buffer for each recipient during reception. We found the optimal value
> for this, considering the most relevant skb pool, to be 3744 bytes.
> 
> Acked-by: Ying Xue <ying.xue@ericsson.com>
> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>

Applied, thanks Jon.

^ permalink raw reply

* Re: [PATCH net-next v2 8/8] net: dummy: remove fake SR-IOV functionality
From: Jakub Kicinski @ 2017-12-01 20:19 UTC (permalink / raw)
  To: Phil Sutter
  Cc: netdev, davem, daniel, alexei.starovoitov, jiri, oss-drivers,
	Sabrina Dubroca
In-Reply-To: <20171201134634.GR32305@orbyte.nwl.cc>

On Fri, 1 Dec 2017 14:46:34 +0100, Phil Sutter wrote:
> On Thu, Nov 30, 2017 at 05:35:40PM -0800, Jakub Kicinski wrote:
> > netdevsim driver seems like a better place for fake SR-IOV
> > functionality.  Remove the code previously added to dummy.
> > 
> > Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> > Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>  
> 
> Acked-by: Phil Sutter <phil@nwl.cc>

Thanks!

Did you have an opportunity to run your tests against this?  I didn't
find anything that uses dummy's SR-IOV in selftests.

^ permalink raw reply

* Re: [PATCH 0/4] SFP/phylink fixes
From: David Miller @ 2017-12-01 20:18 UTC (permalink / raw)
  To: linux; +Cc: andrew, f.fainelli, netdev
In-Reply-To: <20171130135835.GC10595@n2100.armlinux.org.uk>

From: Russell King - ARM Linux <linux@armlinux.org.uk>
Date: Thu, 30 Nov 2017 13:58:35 +0000

> Here are four phylink fixes:
> - the "options" is a big-endian value, we must test the bits taking the
>   endian-ness into account.
> - improve the handling of RX_LOS polarity, taking no RX_LOS polarity
>   bits set to mean there is no RX_LOS functionality provided.
> - do not report modules that require the address mode switching as
>   supporting SFF8472.
> - ensure that the mac_link_down() function is called when phylink_stop()
>   is called.

Series applied, thank you.

^ permalink raw reply

* Re: [PATCH] net: phy-micrel: check return code in flp center function
From: David Miller @ 2017-12-01 20:17 UTC (permalink / raw)
  To: muvarov; +Cc: netdev, andrew, f.fainelli
In-Reply-To: <1512036509-18924-1-git-send-email-muvarov@gmail.com>

From: Max Uvarov <muvarov@gmail.com>
Date: Thu, 30 Nov 2017 13:08:29 +0300

> Fix obvious typo that first return value is set but not checked.
> 
> Signed-off-by: Max Uvarov <muvarov@gmail.com>

Applied, thank you.

^ permalink raw reply

* Re: [PATCH net v2] tipc: call tipc_rcv() only if bearer is up in tipc_udp_recv()
From: David Miller @ 2017-12-01 20:14 UTC (permalink / raw)
  To: tommi.t.rantala
  Cc: jon.maloy, ying.xue, netdev, tipc-discussion, linux-kernel
In-Reply-To: <20171129104842.30781-1-tommi.t.rantala@nokia.com>

From: Tommi Rantala <tommi.t.rantala@nokia.com>
Date: Wed, 29 Nov 2017 12:48:42 +0200

> Remove the second tipc_rcv() call in tipc_udp_recv(). We have just
> checked that the bearer is not up, and calling tipc_rcv() with a bearer
> that is not up leads to a TIPC div-by-zero crash in
> tipc_node_calculate_timer(). The crash is rare in practice, but can
> happen like this:
> 
>   We're enabling a bearer, but it's not yet up and fully initialized.
>   At the same time we receive a discovery packet, and in tipc_udp_recv()
>   we end up calling tipc_rcv() with the not-yet-initialized bearer,
>   causing later the div-by-zero crash in tipc_node_calculate_timer().
> 
> Jon Maloy explains the impact of removing the second tipc_rcv() call:
>   "link setup in the worst case will be delayed until the next arriving
>    discovery messages, 1 sec later, and this is an acceptable delay."
> 
> As the tipc_rcv() call is removed, just leave the function via the
> rcu_out label, so that we will kfree_skb().
 ...
> Fixes: c9b64d492b1f ("tipc: add replicast peer discovery")
> Signed-off-by: Tommi Rantala <tommi.t.rantala@nokia.com>
> Cc: Jon Maloy <jon.maloy@ericsson.com>

Applied and queued up for -stable, thanks.

^ permalink raw reply

* Re: [PATCH net-next v2 7/8] netdevsim: add SR-IOV functionality
From: Jakub Kicinski @ 2017-12-01 20:14 UTC (permalink / raw)
  To: Phil Sutter
  Cc: netdev, davem, daniel, alexei.starovoitov, jiri, oss-drivers,
	Sabrina Dubroca
In-Reply-To: <20171201134306.GQ32305@orbyte.nwl.cc>

On Fri, 1 Dec 2017 14:43:06 +0100, Phil Sutter wrote:
> On Thu, Nov 30, 2017 at 05:35:39PM -0800, Jakub Kicinski wrote:
> [...]
> > +static int nsim_vfs_enable(struct netdevsim *ns, unsigned int num_vfs)
> > +{
> > +	ns->vfconfigs = kcalloc(num_vfs, sizeof(struct nsim_vf_config),
> > +				GFP_KERNEL);
> > +	if (!ns->vfconfigs)
> > +		return -ENOMEM;
> > +	ns->num_vfs = num_vfs;
> > +
> > +	return 0;
> > +}
> > +
> > +static void nsim_vfs_disable(struct netdevsim *ns)
> > +{
> > +	kfree(ns->vfconfigs);
> > +	ns->vfconfigs = NULL;
> > +	ns->num_vfs = 0;
> > +}  
> 
> Why not something like:
> 
> | static int nsim_vfs_set(struct netdevsim *ns, unsigned int num_vfs)
> | {
> | 	void *ptr = krealloc(ns->vfconfigs,
> | 			     num_vfs * sizeof(struct nsim_vf_config),
> | 			     GFP_KERNEL);
> | 
> | 	if (!ptr)
> | 		return -ENOMEM;
> | 
> | 	ns->vfconfigs = ptr;
> | 	ns->num_vfs = num_vfs;
> | 	return 0;
> | }

Um.  It either frees or allocates, never reallocates so I felt realloc
is misleading.  ZERO_SIZE_PTR is less clearly a NULL than a NULL.  I
will have to specify __GFP_ZERO.  It's not a calloc so there could be
potentially some overflows?

> > +static ssize_t
> > +nsim_numvfs_store(struct device *dev, struct device_attribute *attr,
> > +		  const char *buf, size_t count)
> > +{
> > +	struct netdevsim *ns = to_nsim(dev);
> > +	unsigned int num_vfs;
> > +	int ret;
> > +
> > +	ret = kstrtouint(buf, 0, &num_vfs);
> > +	if (ret)
> > +		return ret;
> > +
> > +	rtnl_lock();
> > +	if (ns->num_vfs == num_vfs)
> > +		goto exit_good;  
> 
> Then replace this:
> 
> > +	if (ns->num_vfs && num_vfs) {
> > +		ret = -EBUSY;
> > +		goto exit_unlock;
> > +	}
> > +
> > +	if (num_vfs) {
> > +		ret = nsim_vfs_enable(ns, num_vfs);
> > +		if (ret)
> > +			goto exit_unlock;
> > +	} else {
> > +		nsim_vfs_disable(ns);
> > +	}  
> 
> with just:
> 
> |	nsim_vfs_set(ns, num_vfs);

I'm trying to mirror the PCI subsystem behaviour here, which only
allows enable or disable, not increase.  I felt we should follow how
real devices behave:

	/* enable VFs */
	if (pdev->sriov->num_VFs) {
		dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n",
			 pdev->sriov->num_VFs, num_vfs);
		return -EBUSY;
	}

So IOW this is intentional.

> > +	ret = count;
> > +exit_unlock:
> > +	rtnl_unlock();
> > +
> > +	return ret;
> > +}  
> 
> [...]
> 
> > +static void nsim_free(struct net_device *dev)
> > +{
> > +	struct netdevsim *ns = netdev_priv(dev);
> > +
> > +	device_unregister(&ns->dev);
> >  }  
> 
> Shouldn't this also kfree(ns->vfconfigs)?

It's in uninit, I will move it to release.

^ permalink raw reply

* Re: netfilter: xt_bpf: Fix XT_BPF_MODE_FD_PINNED mode of 'xt_bpf_info_v1'
From: Daniel Borkmann @ 2017-12-01 20:13 UTC (permalink / raw)
  To: Linus Torvalds, Al Viro
  Cc: Kees Cook, Shmulik Ladkani, Willem de Bruijn, Pablo Neira Ayuso,
	David Miller, LKML, Network Development, Christoph Hellwig,
	Thomas Garnier, Jann Horn
In-Reply-To: <CA+55aFx4WEm5Feu7S8Z_73Gfsym6aBFpT3iGZXS5QyMQvgkWtA@mail.gmail.com>

On 12/01/2017 07:28 PM, Linus Torvalds wrote:
> [ Sorry for HTML email crud - traveling and on mobile right now ]
> 
> On Nov 30, 2017 23:54, "Al Viro" <viro@zeniv.linux.org.uk> wrote:
> 
> Would cause problems for tracepoints in there, though.  And that, BTW,
> is precisely why I don't want tracepoints in core VFS, TYVM - makes
> restructuring the code harder...
> 
> Just ignore them, see if anybody notices, and then they can add them back.
> Tracepoints shouldn't hold up kernel development, and I doubt these are
> ones that could be noticed by normal users.

Yep, agree, if it really gets in the way, then lets remove them for
now. After all, that was what was decided anyway.

^ permalink raw reply

* [PATCH iproute2 net-next] iplink: allow configuring GSO max values
From: Stephen Hemminger @ 2017-12-01 20:13 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

This allows sending GSO maximum values when configuring a device.
The values are advisory. Most devices will ignore them but for some
pseudo devices such as veth pairs they can be set.

Example:
	# ip link add dev vm1 type veth peer name vm2 gso_max_size 32768

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 ip/iplink.c           | 19 ++++++++++++++++++-
 man/man8/ip-link.8.in | 13 +++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/ip/iplink.c b/ip/iplink.c
index 0a8eb56fb252..6379b16a14f5 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -97,7 +97,8 @@ void iplink_usage(void)
 		"			  [ master DEVICE ][ vrf NAME ]\n"
 		"			  [ nomaster ]\n"
 		"			  [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
-		"	                  [ protodown { on | off } ]\n"
+		"			  [ protodown { on | off } ]\n"
+		"			  [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
 		"\n"
 		"       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
 
@@ -848,6 +849,22 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 				return on_off("protodown", *argv);
 			addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
 				 proto_down);
+		} else if (strcmp(*argv, "gso_max_size") == 0) {
+			unsigned int max_size;
+
+			NEXT_ARG();
+			if (get_unsigned(&max_size, *argv, 0) || max_size > UINT16_MAX)
+				invarg("Invalid \"gso_max_size\" value\n",
+				       *argv);
+			addattr32(&req->n, sizeof(*req), IFLA_GSO_MAX_SIZE, max_size);
+		} else if (strcmp(*argv, "gso_max_segs") == 0) {
+			unsigned int max_segs;
+
+			NEXT_ARG();
+			if (get_unsigned(&max_segs, *argv, 0) || max_segs > UINT16_MAX)
+				invarg("Invalid \"gso_max_segs\" value\n",
+				       *argv);
+			addattr32(&req->n, sizeof(*req), IFLA_GSO_MAX_SEGS, max_segs);
 		} else {
 			if (matches(*argv, "help") == 0)
 				usage();
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index a6a10e577b1f..0db2582e19f7 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -36,6 +36,11 @@ ip-link \- network device configuration
 .RB "[ " numrxqueues
 .IR QUEUE_COUNT " ]"
 .br
+.BR "[" gso_max_size
+.IR BYTES " ]"
+.RB "[ " gso_max_segs
+.IR SEGMENTS " ]"
+.br
 .BI type " TYPE"
 .RI "[ " ARGS " ]"
 
@@ -343,6 +348,14 @@ specifies the number of transmit queues for new device.
 specifies the number of receive queues for new device.
 
 .TP
+.BI gso_max_size " BYTES "
+specifies the recommended maximum size of a Generic Segment Offload packet the new device should accept.
+
+.TP
+.BI gso_max_segs " SEGMENTS "
+specifies the recommended maximum number of a Generic Segment Offload segments the new device should accept.
+
+.TP
 .BI index " IDX "
 specifies the desired index of the new virtual device. The link creation fails, if the index is busy.
 
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH net] tcp/dccp: block bh before arming time_wait timer
From: David Miller @ 2017-12-01 20:12 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, maze
In-Reply-To: <1512151616.19682.44.camel@gmail.com>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 01 Dec 2017 10:06:56 -0800

> From: Eric Dumazet <edumazet@google.com>
> 
> Maciej Żenczykowski reported some panics in tcp_twsk_destructor()
> that might be caused by the following bug.
> 
> timewait timer is pinned to the cpu, because we want to transition
> timwewait refcount from 0 to 4 in one go, once everything has been
> initialized.
> 
> At the time commit ed2e92394589 ("tcp/dccp: fix timewait races in timer
> handling") was merged, TCP was always running from BH habdler.
> 
> After commit 5413d1babe8f ("net: do not block BH while processing
> socket backlog") we definitely can run tcp_time_wait() from process
> context.
> 
> We need to block BH in the critical section so that the pinned timer
> has still its purpose.
> 
> This bug is more likely to happen under stress and when very small RTO
> are used in datacenter flows.
> 
> Fixes: 5413d1babe8f ("net: do not block BH while processing socket backlog")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Reported-by: Maciej Żenczykowski <maze@google.com>

Applied and queued up for -stable, thanks Eric.

^ permalink raw reply

* [PATCH net-next 2/2] veth: allow configuring GSO maximums
From: Stephen Hemminger @ 2017-12-01 20:11 UTC (permalink / raw)
  To: davem; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20171201201158.25594-1-sthemmin@microsoft.com>

Veth's can be used in environments (like Azure) where the underlying
network device is impacted by large GSO packets. This patch allows
gso maximum values to be passed in when creating the device via
netlink.

In theory, other pseudo devices could also use netlink attributes
to set GSO maximums but for now veth is what has been observed
to be an issue.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 drivers/net/veth.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index f5438d0978ca..510c058ba227 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -410,6 +410,26 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
 	if (ifmp && (dev->ifindex != 0))
 		peer->ifindex = ifmp->ifi_index;
 
+	if (tbp[IFLA_GSO_MAX_SIZE]) {
+		u32 max_size = nla_get_u32(tbp[IFLA_GSO_MAX_SIZE]);
+
+		if (max_size > GSO_MAX_SIZE)
+			return -EINVAL;
+
+		peer->gso_max_size = max_size;
+		dev->gso_max_size = max_size;
+	}
+
+	if (tbp[IFLA_GSO_MAX_SEGS]) {
+		u32 max_segs = nla_get_u32(tbp[IFLA_GSO_MAX_SEGS]);
+
+		if (max_segs > GSO_MAX_SEGS)
+			return -EINVAL;
+
+		peer->gso_max_segs = max_segs;
+		dev->gso_max_segs = max_segs;
+	}
+
 	err = register_netdevice(peer);
 	put_net(net);
 	net = NULL;
-- 
2.11.0

^ permalink raw reply related

* [PATCH net-next 1/2] rtnetlink: allow GSO maximums to be passed to device
From: Stephen Hemminger @ 2017-12-01 20:11 UTC (permalink / raw)
  To: davem; +Cc: netdev, Stephen Hemminger
In-Reply-To: <20171201201158.25594-1-sthemmin@microsoft.com>

Allow GSO maximum segments and size as netlink parameters on input.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 net/core/rtnetlink.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index dabba2a91fc8..8138194c5f81 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1569,6 +1569,8 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
 	[IFLA_PROMISCUITY]	= { .type = NLA_U32 },
 	[IFLA_NUM_TX_QUEUES]	= { .type = NLA_U32 },
 	[IFLA_NUM_RX_QUEUES]	= { .type = NLA_U32 },
+	[IFLA_GSO_MAX_SEGS]	= { .type = NLA_U32 },
+	[IFLA_GSO_MAX_SIZE]	= { .type = NLA_U32 },
 	[IFLA_PHYS_PORT_ID]	= { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
 	[IFLA_CARRIER_CHANGES]	= { .type = NLA_U32 },  /* ignored */
 	[IFLA_PHYS_SWITCH_ID]	= { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN },
-- 
2.11.0

^ permalink raw reply related


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