Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 06/10] net: ipv6: Convert inet socket lookups to new struct
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Convert the various inet6_lookup functions to use the new sk_lookup
struct.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/inet6_hashtables.h      | 39 +++++++-------------
 net/dccp/ipv6.c                     | 22 ++++++++----
 net/ipv4/inet_diag.c                | 19 ++++++----
 net/ipv4/udp_diag.c                 |  2 ++
 net/ipv6/inet6_hashtables.c         | 72 +++++++++++++++++++------------------
 net/ipv6/netfilter/nf_socket_ipv6.c |  5 ++-
 net/ipv6/tcp_ipv6.c                 | 60 +++++++++++++++++++++----------
 net/netfilter/xt_TPROXY.c           |  8 ++---
 8 files changed, 125 insertions(+), 102 deletions(-)

diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index b87becacd9d3..15db41272ff2 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -46,63 +46,50 @@ static inline unsigned int __inet6_ehashfn(const u32 lhash,
  */
 struct sock *__inet6_lookup_established(struct net *net,
 					struct inet_hashinfo *hashinfo,
-					const struct in6_addr *saddr,
-					const __be16 sport,
-					const struct in6_addr *daddr,
-					const u16 hnum, const int dif);
+					const struct sk_lookup *params);
 
 struct sock *inet6_lookup_listener(struct net *net,
 				   struct inet_hashinfo *hashinfo,
 				   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);
+				   struct sk_lookup *params);
 
 static inline struct sock *__inet6_lookup(struct net *net,
 					  struct inet_hashinfo *hashinfo,
 					  struct sk_buff *skb, int doff,
-					  const struct in6_addr *saddr,
-					  const __be16 sport,
-					  const struct in6_addr *daddr,
-					  const u16 hnum,
-					  const int dif,
+					  struct sk_lookup *params,
 					  bool *refcounted)
 {
-	struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr,
-						sport, daddr, hnum, dif);
+	struct sock *sk = __inet6_lookup_established(net, hashinfo, params);
+
 	*refcounted = true;
 	if (sk)
 		return sk;
 	*refcounted = false;
-	return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
-				     daddr, hnum, dif);
+	return inet6_lookup_listener(net, hashinfo, skb, doff, params);
 }
 
 static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
 					      struct sk_buff *skb, int doff,
-					      const __be16 sport,
-					      const __be16 dport,
-					      int iif,
+					      struct sk_lookup *params,
 					      bool *refcounted)
 {
 	struct sock *sk = skb_steal_sock(skb);
 
+	params->saddr.ipv6 = &ipv6_hdr(skb)->saddr,
+	params->daddr.ipv6 = &ipv6_hdr(skb)->daddr,
+	params->hnum = ntohs(params->dport),
+
 	*refcounted = true;
 	if (sk)
 		return sk;
 
 	return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb,
-			      doff, &ipv6_hdr(skb)->saddr, sport,
-			      &ipv6_hdr(skb)->daddr, ntohs(dport),
-			      iif, refcounted);
+			      doff, params, refcounted);
 }
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 			  struct sk_buff *skb, int doff,
-			  const struct in6_addr *saddr, const __be16 sport,
-			  const struct in6_addr *daddr, const __be16 dport,
-			  const int dif);
+			  struct sk_lookup *params);
 
 int inet6_hash(struct sock *sk);
 #endif /* IS_ENABLED(CONFIG_IPV6) */
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index c376af5bfdfb..e92f10a832dd 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -70,6 +70,11 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 			u8 type, u8 code, int offset, __be32 info)
 {
 	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
+	struct sk_lookup params = {
+		.saddr.ipv6 = &hdr->daddr,
+		.daddr.ipv6 = &hdr->saddr,
+		.dif = inet6_iif(skb),
+	};
 	const struct dccp_hdr *dh;
 	struct dccp_sock *dp;
 	struct ipv6_pinfo *np;
@@ -86,11 +91,10 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
 	dh = (struct dccp_hdr *)(skb->data + offset);
 
-	sk = __inet6_lookup_established(net, &dccp_hashinfo,
-					&hdr->daddr, dh->dccph_dport,
-					&hdr->saddr, ntohs(dh->dccph_sport),
-					inet6_iif(skb));
-
+	params.sport = dh->dccph_dport;
+	params.dport = dh->dccph_sport;
+	params.hnum = ntohs(dh->dccph_sport);
+	sk = __inet6_lookup_established(net, &dccp_hashinfo, &params);
 	if (!sk) {
 		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
 				  ICMP6_MIB_INERRORS);
@@ -656,6 +660,9 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 
 static int dccp_v6_rcv(struct sk_buff *skb)
 {
+	struct sk_lookup params = {
+		.dif = inet6_iif(skb),
+	};
 	const struct dccp_hdr *dh;
 	bool refcounted;
 	struct sock *sk;
@@ -683,10 +690,11 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 	else
 		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
 
+	params.sport = dh->dccph_sport;
+	params.dport = dh->dccph_dport;
 lookup:
 	sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
-			        dh->dccph_sport, dh->dccph_dport,
-				inet6_iif(skb), &refcounted);
+				&params, &refcounted);
 	if (!sk) {
 		dccp_pr_debug("failed to look up flow ID in table and "
 			      "get corresponding socket\n");
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 6c3bc4e408d0..c1ec0d3cc4b9 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -422,13 +422,18 @@ struct sock *inet_diag_find_one_icsk(struct net *net,
 			};
 
 			sk = inet_lookup(net, hashinfo, NULL, 0, &params);
-		} else
-			sk = inet6_lookup(net, hashinfo, NULL, 0,
-					  (struct in6_addr *)req->id.idiag_dst,
-					  req->id.idiag_dport,
-					  (struct in6_addr *)req->id.idiag_src,
-					  req->id.idiag_sport,
-					  req->id.idiag_if);
+		} else {
+			struct sk_lookup params = {
+				.saddr.ipv6 = (struct in6_addr *)req->id.idiag_dst,
+				.daddr.ipv6 = (struct in6_addr *)req->id.idiag_src,
+				.sport = req->id.idiag_dport,
+				.dport = req->id.idiag_sport,
+				.hnum  = ntohs(req->id.idiag_sport),
+				.dif   = req->id.idiag_if,
+			};
+
+			sk = inet6_lookup(net, hashinfo, NULL, 0, &params);
+		}
 	}
 #endif
 	else {
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 10738c10c5ae..bd358f9dde1f 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -60,6 +60,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 			.daddr.ipv6 = (struct in6_addr *)req->id.idiag_dst,
 			.sport = req->id.idiag_sport,
 			.dport = req->id.idiag_dport,
+			.hnum  = ntohs(req->id.idiag_dport),
 			.dif   =  req->id.idiag_if,
 		};
 
@@ -221,6 +222,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
 				.daddr.ipv6 = (struct in6_addr *)req->id.idiag_src,
 				.sport = req->id.idiag_dport,
 				.dport = req->id.idiag_sport,
+				.hnum  = ntohs(req->id.idiag_sport),
 				.dif   = req->id.idiag_if,
 			};
 
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index b13b8f93079d..878c03094f2e 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -52,33 +52,35 @@ u32 inet6_ehashfn(const struct net *net,
  */
 struct sock *__inet6_lookup_established(struct net *net,
 					struct inet_hashinfo *hashinfo,
-					   const struct in6_addr *saddr,
-					   const __be16 sport,
-					   const struct in6_addr *daddr,
-					   const u16 hnum,
-					   const int dif)
+					const struct sk_lookup *params)
 {
+	const __portpair ports = INET_COMBINED_PORTS(params->sport,
+						     params->hnum);
+	const struct in6_addr *saddr = params->saddr.ipv6;
+	const struct in6_addr *daddr = params->daddr.ipv6;
 	struct sock *sk;
 	const struct hlist_nulls_node *node;
-	const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
+
 	/* Optimize here for direct hit, only listening connections can
 	 * have wildcards anyways.
 	 */
-	unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport);
+	unsigned int hash = inet6_ehashfn(net, daddr, params->hnum,
+					  saddr, params->sport);
 	unsigned int slot = hash & hashinfo->ehash_mask;
 	struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
 
-
 begin:
 	sk_nulls_for_each_rcu(sk, node, &head->chain) {
 		if (sk->sk_hash != hash)
 			continue;
-		if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif))
+		if (!INET6_MATCH(sk, net, saddr, daddr, ports,
+				 params->dif))
 			continue;
 		if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
 			goto out;
 
-		if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) {
+		if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports,
+				 params->dif))) {
 			sock_gen_put(sk);
 			goto begin;
 		}
@@ -94,26 +96,27 @@ struct sock *__inet6_lookup_established(struct net *net,
 EXPORT_SYMBOL(__inet6_lookup_established);
 
 static inline int compute_score(struct sock *sk, struct net *net,
-				const unsigned short hnum,
-				const struct in6_addr *daddr,
-				const int dif, bool exact_dif)
+				const struct sk_lookup *params)
 {
 	int score = -1;
 
-	if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum &&
+	if (net_eq(sock_net(sk), net) &&
+	    inet_sk(sk)->inet_num == params->hnum &&
 	    sk->sk_family == PF_INET6) {
+		int rc;
 
 		score = 1;
 		if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
-			if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
+			if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr,
+					     params->daddr.ipv6))
 				return -1;
 			score++;
 		}
-		if (sk->sk_bound_dev_if || exact_dif) {
-			if (sk->sk_bound_dev_if != dif)
-				return -1;
+		rc = sk_lookup_device_cmp(sk, params);
+		if (rc < 0)
+			return -1;
+		if (rc > 0)
 			score++;
-		}
 		if (sk->sk_incoming_cpu == raw_smp_processor_id())
 			score++;
 	}
@@ -122,26 +125,27 @@ static inline int compute_score(struct sock *sk, struct net *net,
 
 /* called with rcu_read_lock() */
 struct sock *inet6_lookup_listener(struct net *net,
-		struct inet_hashinfo *hashinfo,
-		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)
+				   struct inet_hashinfo *hashinfo,
+				   struct sk_buff *skb, int doff,
+				   struct sk_lookup *params)
 {
-	unsigned int hash = inet_lhashfn(net, hnum);
+	unsigned int hash = inet_lhashfn(net, params->hnum);
 	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 	int score, hiscore = 0, matches = 0, reuseport = 0;
-	bool exact_dif = inet6_exact_dif_match(net, skb);
 	struct sock *sk, *result = NULL;
 	u32 phash = 0;
 
+	params->exact_dif = inet6_exact_dif_match(net, skb);
+
 	sk_for_each(sk, &ilb->head) {
-		score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > hiscore) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				phash = inet6_ehashfn(net, daddr, hnum,
-						      saddr, sport);
+				phash = inet6_ehashfn(net, params->daddr.ipv6,
+						      params->hnum,
+						      params->saddr.ipv6,
+						      params->sport);
 				result = reuseport_select_sock(sk, phash,
 							       skb, doff);
 				if (result)
@@ -163,15 +167,12 @@ EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 			  struct sk_buff *skb, int doff,
-			  const struct in6_addr *saddr, const __be16 sport,
-			  const struct in6_addr *daddr, const __be16 dport,
-			  const int dif)
+			  struct sk_lookup *params)
 {
 	struct sock *sk;
 	bool refcounted;
 
-	sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
-			    ntohs(dport), dif, &refcounted);
+	sk = __inet6_lookup(net, hashinfo, skb, doff, params, &refcounted);
 	if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt))
 		sk = NULL;
 	return sk;
@@ -203,7 +204,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
 		if (sk2->sk_hash != hash)
 			continue;
 
-		if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) {
+		if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports,
+				       dif))) {
 			if (sk2->sk_state == TCP_TIME_WAIT) {
 				tw = inet_twsk(sk2);
 				if (twsk_unique(sk, sk2, twp))
diff --git a/net/ipv6/netfilter/nf_socket_ipv6.c b/net/ipv6/netfilter/nf_socket_ipv6.c
index c1c193103063..1d815e0933b7 100644
--- a/net/ipv6/netfilter/nf_socket_ipv6.c
+++ b/net/ipv6/netfilter/nf_socket_ipv6.c
@@ -91,14 +91,13 @@ nf_socket_get_sock_v6(struct net *net, struct sk_buff *skb, int doff,
 		.daddr.ipv6 = daddr,
 		.sport = sport,
 		.dport = dport,
+		.hnum  = ntohs(dport),
 		.dif   = in->ifindex,
 	};
 
 	switch (protocol) {
 	case IPPROTO_TCP:
-		return inet6_lookup(net, &tcp_hashinfo, skb, doff,
-				    saddr, sport, daddr, dport,
-				    in->ifindex);
+		return inet6_lookup(net, &tcp_hashinfo, skb, doff, &params);
 	case IPPROTO_UDP:
 		return udp6_lib_lookup(net, &params);
 	}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2968a33cca7d..19fee98e1ae0 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -45,6 +45,7 @@
 #include <linux/random.h>
 
 #include <net/tcp.h>
+#include <net/inet_hashtables.h>
 #include <net/ndisc.h>
 #include <net/inet6_hashtables.h>
 #include <net/inet6_connection_sock.h>
@@ -338,6 +339,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 {
 	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
 	const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
+	struct sk_lookup params = {
+		.saddr.ipv6 = &hdr->daddr,
+		.daddr.ipv6 = &hdr->saddr,
+		.sport = th->dest,
+		.hnum  = ntohs(th->source),
+		.dif   = skb->dev->ifindex,
+	};
 	struct net *net = dev_net(skb->dev);
 	struct request_sock *fastopen;
 	struct ipv6_pinfo *np;
@@ -347,11 +355,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	bool fatal;
 	int err;
 
-	sk = __inet6_lookup_established(net, &tcp_hashinfo,
-					&hdr->daddr, th->dest,
-					&hdr->saddr, ntohs(th->source),
-					skb->dev->ifindex);
-
+	sk = __inet6_lookup_established(net, &tcp_hashinfo, &params);
 	if (!sk) {
 		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
 				  ICMP6_MIB_INERRORS);
@@ -907,6 +911,14 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
 	if (sk && sk_fullsock(sk)) {
 		key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr);
 	} else if (hash_location) {
+		struct sk_lookup params = {
+			.saddr.ipv6 = &ipv6h->saddr,
+			.daddr.ipv6 = &ipv6h->daddr,
+			.sport = th->source,
+			.hnum = ntohs(th->source),
+			.dif  = tcp_v6_iif(skb),
+		};
+
 		/*
 		 * active side is lost. Try to find listening socket through
 		 * source port, and then find md5 key through listening socket.
@@ -915,10 +927,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
 		 * no RST generated if md5 hash doesn't match.
 		 */
 		sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
-					   &tcp_hashinfo, NULL, 0,
-					   &ipv6h->saddr,
-					   th->source, &ipv6h->daddr,
-					   ntohs(th->source), tcp_v6_iif(skb));
+					   &tcp_hashinfo, NULL, 0, &params);
 		if (!sk1)
 			goto out;
 
@@ -1403,6 +1412,9 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 	struct sock *sk;
 	int ret;
 	struct net *net = dev_net(skb->dev);
+	struct sk_lookup params = {
+		.dif = inet6_iif(skb),
+	};
 
 	if (skb->pkt_type != PACKET_HOST)
 		goto discard_it;
@@ -1428,10 +1440,11 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 	th = (const struct tcphdr *)skb->data;
 	hdr = ipv6_hdr(skb);
 
+	params.sport = th->source;
+	params.dport = th->dest;
 lookup:
 	sk = __inet6_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th),
-				th->source, th->dest, inet6_iif(skb),
-				&refcounted);
+				&params, &refcounted);
 	if (!sk)
 		goto no_tcp_socket;
 
@@ -1558,13 +1571,17 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 	switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
 	case TCP_TW_SYN:
 	{
+		struct sk_lookup params = {
+			.saddr.ipv6 = &ipv6_hdr(skb)->saddr,
+			.daddr.ipv6 = &ipv6_hdr(skb)->daddr,
+			.sport = th->source,
+			.hnum = ntohs(th->dest),
+			.dif  = tcp_v6_iif(skb),
+		};
 		struct sock *sk2;
 
 		sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
-					    skb, __tcp_hdrlen(th),
-					    &ipv6_hdr(skb)->saddr, th->source,
-					    &ipv6_hdr(skb)->daddr,
-					    ntohs(th->dest), tcp_v6_iif(skb));
+					    skb, __tcp_hdrlen(th), &params);
 		if (sk2) {
 			struct inet_timewait_sock *tw = inet_twsk(sk);
 			inet_twsk_deschedule_put(tw);
@@ -1591,6 +1608,10 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 
 static void tcp_v6_early_demux(struct sk_buff *skb)
 {
+	/* Note : We use inet6_iif() here, not tcp_v6_iif() */
+	struct sk_lookup params = {
+		.dif = inet6_iif(skb),
+	};
 	const struct ipv6hdr *hdr;
 	const struct tcphdr *th;
 	struct sock *sk;
@@ -1607,11 +1628,12 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
 	if (th->doff < sizeof(struct tcphdr) / 4)
 		return;
 
-	/* Note : We use inet6_iif() here, not tcp_v6_iif() */
+	params.saddr.ipv6 = &hdr->saddr,
+	params.daddr.ipv6 = &hdr->daddr,
+	params.sport = th->source,
+	params.hnum = ntohs(th->dest),
 	sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
-					&hdr->saddr, th->source,
-					&hdr->daddr, ntohs(th->dest),
-					inet6_iif(skb));
+					&params);
 	if (sk) {
 		skb->sk = sk;
 		skb->destructor = sock_edemux;
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 56bb40544035..3ee75189d1c3 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -193,6 +193,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
 		.daddr.ipv6 = daddr,
 		.sport = sport,
 		.dport = dport,
+		.hnum  = ntohs(dport),
 		.dif   = in->ifindex,
 	};
 	struct sock *sk;
@@ -205,9 +206,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
 			tcph = hp;
 			sk = inet6_lookup_listener(net, &tcp_hashinfo, skb,
 						   thoff + __tcp_hdrlen(tcph),
-						   saddr, sport,
-						   daddr, ntohs(dport),
-						   in->ifindex);
+						   &params);
 
 			if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 				sk = NULL;
@@ -219,8 +218,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
 			break;
 		case NFT_LOOKUP_ESTABLISHED:
 			sk = __inet6_lookup_established(net, &tcp_hashinfo,
-							saddr, sport, daddr, ntohs(dport),
-							in->ifindex);
+							&params);
 			break;
 		default:
 			BUG();
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 05/10] net: ipv6: Convert udp socket lookups to new struct
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Convert udp6_lib_lookup and __udp6_lib_lookup to use the new sk_lookup
struct.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/udp.h                   |  12 +--
 net/ipv4/udp_diag.c                 |  33 ++++---
 net/ipv6/netfilter/nf_socket_ipv6.c |  11 ++-
 net/ipv6/udp.c                      | 177 +++++++++++++++++++-----------------
 net/netfilter/xt_TPROXY.c           |  10 +-
 5 files changed, 135 insertions(+), 108 deletions(-)

diff --git a/include/net/udp.h b/include/net/udp.h
index 5e0ff095dc6d..c5a75e9422c6 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -288,15 +288,9 @@ struct sock *__udp4_lib_lookup(struct net *net, struct sk_lookup *params,
 			       struct udp_table *tbl, struct sk_buff *skb);
 struct sock *udp4_lib_lookup_skb(struct sk_buff *skb,
 				 __be16 sport, __be16 dport);
-struct sock *udp6_lib_lookup(struct net *net,
-			     const struct in6_addr *saddr, __be16 sport,
-			     const struct in6_addr *daddr, __be16 dport,
-			     int dif);
-struct sock *__udp6_lib_lookup(struct net *net,
-			       const struct in6_addr *saddr, __be16 sport,
-			       const struct in6_addr *daddr, __be16 dport,
-			       int dif, struct udp_table *tbl,
-			       struct sk_buff *skb);
+struct sock *udp6_lib_lookup(struct net *net, struct sk_lookup *params);
+struct sock *__udp6_lib_lookup(struct net *net, struct sk_lookup *params,
+			       struct udp_table *tbl, struct sk_buff *skb);
 struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
 				 __be16 sport, __be16 dport);
 
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index d7f6af42ebcc..10738c10c5ae 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -54,13 +54,17 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 		sk = __udp4_lib_lookup(net, &params, tbl, NULL);
 	}
 #if IS_ENABLED(CONFIG_IPV6)
-	else if (req->sdiag_family == AF_INET6)
-		sk = __udp6_lib_lookup(net,
-				(struct in6_addr *)req->id.idiag_src,
-				req->id.idiag_sport,
-				(struct in6_addr *)req->id.idiag_dst,
-				req->id.idiag_dport,
-				req->id.idiag_if, tbl, NULL);
+	else if (req->sdiag_family == AF_INET6) {
+		struct sk_lookup params = {
+			.saddr.ipv6 = (struct in6_addr *)req->id.idiag_src,
+			.daddr.ipv6 = (struct in6_addr *)req->id.idiag_dst,
+			.sport = req->id.idiag_sport,
+			.dport = req->id.idiag_dport,
+			.dif   =  req->id.idiag_if,
+		};
+
+		sk = __udp6_lib_lookup(net, &params, tbl, NULL);
+	}
 #endif
 	if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 		sk = NULL;
@@ -212,12 +216,15 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
 
 			sk = __udp4_lib_lookup(net, &params, tbl, NULL);
 		} else {
-			sk = __udp6_lib_lookup(net,
-					(struct in6_addr *)req->id.idiag_dst,
-					req->id.idiag_dport,
-					(struct in6_addr *)req->id.idiag_src,
-					req->id.idiag_sport,
-					req->id.idiag_if, tbl, NULL);
+			struct sk_lookup params = {
+				.saddr.ipv6 = (struct in6_addr *)req->id.idiag_dst,
+				.daddr.ipv6 = (struct in6_addr *)req->id.idiag_src,
+				.sport = req->id.idiag_dport,
+				.dport = req->id.idiag_sport,
+				.dif   = req->id.idiag_if,
+			};
+
+			sk = __udp6_lib_lookup(net, &params, tbl, NULL);
 		}
 	}
 #endif
diff --git a/net/ipv6/netfilter/nf_socket_ipv6.c b/net/ipv6/netfilter/nf_socket_ipv6.c
index ebb2bf84232a..c1c193103063 100644
--- a/net/ipv6/netfilter/nf_socket_ipv6.c
+++ b/net/ipv6/netfilter/nf_socket_ipv6.c
@@ -86,14 +86,21 @@ nf_socket_get_sock_v6(struct net *net, struct sk_buff *skb, int doff,
 		      const __be16 sport, const __be16 dport,
 		      const struct net_device *in)
 {
+	struct sk_lookup params = {
+		.saddr.ipv6 = saddr,
+		.daddr.ipv6 = daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = in->ifindex,
+	};
+
 	switch (protocol) {
 	case IPPROTO_TCP:
 		return inet6_lookup(net, &tcp_hashinfo, skb, doff,
 				    saddr, sport, daddr, dport,
 				    in->ifindex);
 	case IPPROTO_UDP:
-		return udp6_lib_lookup(net, saddr, sport, daddr, dport,
-				       in->ifindex);
+		return udp6_lib_lookup(net, &params);
 	}
 
 	return NULL;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5f8b8d766c63..00b362a8bd91 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -67,13 +67,14 @@ static bool udp6_lib_exact_dif_match(struct net *net, struct sk_buff *skb)
 }
 
 static u32 udp6_ehashfn(const struct net *net,
-			const struct in6_addr *laddr,
-			const u16 lport,
-			const struct in6_addr *faddr,
-			const __be16 fport)
+			const struct sk_lookup *params)
 {
+	const struct in6_addr *laddr = params->daddr.ipv6;
+	const struct in6_addr *faddr = params->saddr.ipv6;
 	static u32 udp6_ehash_secret __read_mostly;
 	static u32 udp_ipv6_hash_secret __read_mostly;
+	const __be16 fport = params->sport;
+	const u16 lport = params->hnum;
 
 	u32 lhash, fhash;
 
@@ -127,15 +128,13 @@ static void udp_v6_rehash(struct sock *sk)
 }
 
 static int compute_score(struct sock *sk, struct net *net,
-			 const struct in6_addr *saddr, __be16 sport,
-			 const struct in6_addr *daddr, unsigned short hnum,
-			 int dif, bool exact_dif)
+			 const struct sk_lookup *params)
 {
-	int score;
 	struct inet_sock *inet;
+	int score, rc;
 
 	if (!net_eq(sock_net(sk), net) ||
-	    udp_sk(sk)->udp_port_hash != hnum ||
+	    udp_sk(sk)->udp_port_hash != params->hnum ||
 	    sk->sk_family != PF_INET6)
 		return -1;
 
@@ -143,28 +142,28 @@ static int compute_score(struct sock *sk, struct net *net,
 	inet = inet_sk(sk);
 
 	if (inet->inet_dport) {
-		if (inet->inet_dport != sport)
+		if (inet->inet_dport != params->sport)
 			return -1;
 		score++;
 	}
 
 	if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
-		if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
+		if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, params->daddr.ipv6))
 			return -1;
 		score++;
 	}
 
 	if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
-		if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr))
+		if (!ipv6_addr_equal(&sk->sk_v6_daddr, params->saddr.ipv6))
 			return -1;
 		score++;
 	}
 
-	if (sk->sk_bound_dev_if || exact_dif) {
-		if (sk->sk_bound_dev_if != dif)
-			return -1;
+	rc = sk_lookup_device_cmp(sk, params);
+	if (rc < 0)
+		return -1;
+	if (rc > 0)
 		score++;
-	}
 
 	if (sk->sk_incoming_cpu == raw_smp_processor_id())
 		score++;
@@ -174,10 +173,9 @@ static int compute_score(struct sock *sk, struct net *net,
 
 /* called with rcu_read_lock() */
 static struct sock *udp6_lib_lookup2(struct net *net,
-		const struct in6_addr *saddr, __be16 sport,
-		const struct in6_addr *daddr, unsigned int hnum, int dif,
-		bool exact_dif, struct udp_hslot *hslot2,
-		struct sk_buff *skb)
+				     const struct sk_lookup *params,
+				     struct udp_hslot *hslot2,
+				     struct sk_buff *skb)
 {
 	struct sock *sk, *result;
 	int score, badness, matches = 0, reuseport = 0;
@@ -186,13 +184,11 @@ static struct sock *udp6_lib_lookup2(struct net *net,
 	result = NULL;
 	badness = -1;
 	udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-		score = compute_score(sk, net, saddr, sport,
-				      daddr, hnum, dif, exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > badness) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				hash = udp6_ehashfn(net, daddr, hnum,
-						    saddr, sport);
+				hash = udp6_ehashfn(net, params);
 
 				result = reuseport_select_sock(sk, hash, skb,
 							sizeof(struct udphdr));
@@ -213,30 +209,27 @@ static struct sock *udp6_lib_lookup2(struct net *net,
 }
 
 /* rcu_read_lock() must be held */
-struct sock *__udp6_lib_lookup(struct net *net,
-				      const struct in6_addr *saddr, __be16 sport,
-				      const struct in6_addr *daddr, __be16 dport,
-				      int dif, struct udp_table *udptable,
-				      struct sk_buff *skb)
+struct sock *__udp6_lib_lookup(struct net *net, struct sk_lookup *params,
+			       struct udp_table *udptable, struct sk_buff *skb)
 {
 	struct sock *sk, *result;
-	unsigned short hnum = ntohs(dport);
+	unsigned short hnum = ntohs(params->dport);
 	unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
 	struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-	bool exact_dif = udp6_lib_exact_dif_match(net, skb);
 	int score, badness, matches = 0, reuseport = 0;
 	u32 hash = 0;
 
+	params->hnum = hnum;
+	params->exact_dif = udp6_lib_exact_dif_match(net, skb);
+
 	if (hslot->count > 10) {
-		hash2 = udp6_portaddr_hash(net, daddr, hnum);
+		hash2 = udp6_portaddr_hash(net, params->daddr.ipv6, hnum);
 		slot2 = hash2 & udptable->mask;
 		hslot2 = &udptable->hash2[slot2];
 		if (hslot->count < hslot2->count)
 			goto begin;
 
-		result = udp6_lib_lookup2(net, saddr, sport,
-					  daddr, hnum, dif, exact_dif,
-					  hslot2, skb);
+		result = udp6_lib_lookup2(net, params, hslot2, skb);
 		if (!result) {
 			unsigned int old_slot2 = slot2;
 			hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum);
@@ -249,10 +242,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
 			if (hslot->count < hslot2->count)
 				goto begin;
 
-			result = udp6_lib_lookup2(net, saddr, sport,
-						  daddr, hnum, dif,
-						  exact_dif, hslot2,
-						  skb);
+			result = udp6_lib_lookup2(net, params, hslot2, skb);
 		}
 		return result;
 	}
@@ -260,13 +250,11 @@ struct sock *__udp6_lib_lookup(struct net *net,
 	result = NULL;
 	badness = -1;
 	sk_for_each_rcu(sk, &hslot->head) {
-		score = compute_score(sk, net, saddr, sport, daddr, hnum, dif,
-				      exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > badness) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				hash = udp6_ehashfn(net, daddr, hnum,
-						    saddr, sport);
+				hash = udp6_ehashfn(net, params);
 				result = reuseport_select_sock(sk, hash, skb,
 							sizeof(struct udphdr));
 				if (result)
@@ -292,23 +280,34 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
 {
 	const struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct sock *sk;
+	struct sk_lookup params = {
+		.saddr.ipv6 = &iph->saddr,
+		.daddr.ipv6 = &iph->daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = inet6_iif(skb),
+	};
 
 	sk = skb_steal_sock(skb);
 	if (unlikely(sk))
 		return sk;
-	return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
-				 &iph->daddr, dport, inet6_iif(skb),
-				 udptable, skb);
+
+	return __udp6_lib_lookup(dev_net(skb->dev), &params, udptable, skb);
 }
 
 struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
 				 __be16 sport, __be16 dport)
 {
 	const struct ipv6hdr *iph = ipv6_hdr(skb);
-
-	return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
-				 &iph->daddr, dport, inet6_iif(skb),
-				 &udp_table, skb);
+	struct sk_lookup params = {
+		.saddr.ipv6 = &iph->saddr,
+		.daddr.ipv6 = &iph->daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = inet6_iif(skb),
+	};
+
+	return __udp6_lib_lookup(dev_net(skb->dev), &params, &udp_table, skb);
 }
 EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb);
 
@@ -318,13 +317,11 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb);
 #if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \
     IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) || \
     IS_ENABLED(CONFIG_NF_SOCKET_IPV6)
-struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport,
-			     const struct in6_addr *daddr, __be16 dport, int dif)
+struct sock *udp6_lib_lookup(struct net *net, struct sk_lookup *params)
 {
 	struct sock *sk;
 
-	sk =  __udp6_lib_lookup(net, saddr, sport, daddr, dport,
-				dif, &udp_table, NULL);
+	sk =  __udp6_lib_lookup(net, params, &udp_table, NULL);
 	if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 		sk = NULL;
 	return sk;
@@ -487,16 +484,20 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 {
 	struct ipv6_pinfo *np;
 	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
-	const struct in6_addr *saddr = &hdr->saddr;
-	const struct in6_addr *daddr = &hdr->daddr;
 	struct udphdr *uh = (struct udphdr *)(skb->data+offset);
+	struct sk_lookup params = {
+		.saddr.ipv6 = &hdr->daddr,
+		.daddr.ipv6 = &hdr->saddr,
+		.sport = uh->dest,
+		.dport = uh->source,
+		.dif   = inet6_iif(skb),
+	};
 	struct sock *sk;
 	int harderr;
 	int err;
 	struct net *net = dev_net(skb->dev);
 
-	sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
-			       inet6_iif(skb), udptable, skb);
+	sk = __udp6_lib_lookup(net, &params, udptable, skb);
 	if (!sk) {
 		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
 				  ICMP6_MIB_INERRORS);
@@ -658,21 +659,21 @@ static int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 }
 
 static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk,
-				   __be16 loc_port, const struct in6_addr *loc_addr,
-				   __be16 rmt_port, const struct in6_addr *rmt_addr,
-				   int dif, unsigned short hnum)
+				   struct sk_lookup *params)
 {
+	const struct in6_addr *loc_addr = params->daddr.ipv6;
+	const struct in6_addr *rmt_addr = params->saddr.ipv6;
 	struct inet_sock *inet = inet_sk(sk);
 
 	if (!net_eq(sock_net(sk), net))
 		return false;
 
-	if (udp_sk(sk)->udp_port_hash != hnum ||
+	if (udp_sk(sk)->udp_port_hash != params->hnum ||
 	    sk->sk_family != PF_INET6 ||
-	    (inet->inet_dport && inet->inet_dport != rmt_port) ||
+	    (inet->inet_dport && inet->inet_dport != params->sport) ||
 	    (!ipv6_addr_any(&sk->sk_v6_daddr) &&
 		    !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
-	    (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) ||
+	    (sk->sk_bound_dev_if && sk->sk_bound_dev_if != params->dif) ||
 	    (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
 		    !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)))
 		return false;
@@ -705,9 +706,16 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum);
 	unsigned int offset = offsetof(typeof(*sk), sk_node);
 	unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
-	int dif = inet6_iif(skb);
 	struct hlist_node *node;
 	struct sk_buff *nskb;
+	struct sk_lookup params = {
+		.saddr.ipv6 = saddr,
+		.daddr.ipv6 = daddr,
+		.sport = uh->source,
+		.dport = uh->dest,
+		.hnum  = hnum,
+		.dif   = inet6_iif(skb),
+	};
 
 	if (use_hash2) {
 		hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) &
@@ -719,8 +727,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	}
 
 	sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) {
-		if (!__udp_v6_is_mcast_sock(net, sk, uh->dest, daddr,
-					    uh->source, saddr, dif, hnum))
+		if (!__udp_v6_is_mcast_sock(net, sk, &params))
 			continue;
 		/* If zero checksum and no_check is not on for
 		 * the socket then skip it.
@@ -873,21 +880,22 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 
 
 static struct sock *__udp6_lib_demux_lookup(struct net *net,
-			__be16 loc_port, const struct in6_addr *loc_addr,
-			__be16 rmt_port, const struct in6_addr *rmt_addr,
-			int dif)
+					    const struct sk_lookup *params)
 {
-	unsigned short hnum = ntohs(loc_port);
-	unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum);
+	unsigned short hnum = params->hnum;
+	unsigned int hash2 = udp6_portaddr_hash(net, params->daddr.ipv6, 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);
+	const __portpair ports = INET_COMBINED_PORTS(params->sport, hnum);
 	struct sock *sk;
 
 	udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
 		if (sk->sk_state == TCP_ESTABLISHED &&
-		    INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif))
+		    INET6_MATCH(sk, net, params->saddr.ipv6,
+				params->daddr.ipv6, ports,
+				params->dif))
 			return sk;
+
 		/* Only check first socket in chain */
 		break;
 	}
@@ -900,7 +908,14 @@ static void udp_v6_early_demux(struct sk_buff *skb)
 	const struct udphdr *uh;
 	struct sock *sk;
 	struct dst_entry *dst;
-	int dif = skb->dev->ifindex;
+	struct sk_lookup params = {
+		.saddr.ipv6 = &ipv6_hdr(skb)->saddr,
+		.daddr.ipv6 = &ipv6_hdr(skb)->daddr,
+		.dif = skb->dev->ifindex,
+	};
+
+	if (skb->pkt_type != PACKET_HOST)
+		return;
 
 	if (!pskb_may_pull(skb, skb_transport_offset(skb) +
 	    sizeof(struct udphdr)))
@@ -908,13 +923,11 @@ static void udp_v6_early_demux(struct sk_buff *skb)
 
 	uh = udp_hdr(skb);
 
-	if (skb->pkt_type == PACKET_HOST)
-		sk = __udp6_lib_demux_lookup(net, uh->dest,
-					     &ipv6_hdr(skb)->daddr,
-					     uh->source, &ipv6_hdr(skb)->saddr,
-					     dif);
-	else
-		return;
+	params.dport = uh->dest;
+	params.hnum  = ntohs(uh->dest);
+	params.sport = uh->source;
+
+	sk = __udp6_lib_demux_lookup(net, &params);
 
 	if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
 		return;
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 5cce7eb7dea2..56bb40544035 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -188,6 +188,13 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
 		      const struct net_device *in,
 		      const enum nf_tproxy_lookup_t lookup_type)
 {
+	struct sk_lookup params = {
+		.saddr.ipv6 = saddr,
+		.daddr.ipv6 = daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = in->ifindex,
+	};
 	struct sock *sk;
 	struct tcphdr *tcph;
 
@@ -220,8 +227,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
 		}
 		break;
 	case IPPROTO_UDP:
-		sk = udp6_lib_lookup(net, saddr, sport, daddr, dport,
-				     in->ifindex);
+		sk = udp6_lib_lookup(net, &params);
 		if (sk) {
 			int connected = (sk->sk_state == TCP_ESTABLISHED);
 			int wildcard = ipv6_addr_any(&sk->sk_v6_rcv_saddr);
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 04/10] net: ipv4: Convert raw sockets to sk_lookup
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Convert __raw_v4_lookup to use the new sk_lookup struct

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/raw.h   |  3 +--
 net/ipv4/raw.c      | 72 ++++++++++++++++++++++++++++++++++-------------------
 net/ipv4/raw_diag.c | 15 +++++++----
 3 files changed, 58 insertions(+), 32 deletions(-)

diff --git a/include/net/raw.h b/include/net/raw.h
index 57c33dd22ec4..8d0f0e5d013b 100644
--- a/include/net/raw.h
+++ b/include/net/raw.h
@@ -25,8 +25,7 @@ extern struct proto raw_prot;
 
 extern struct raw_hashinfo raw_v4_hashinfo;
 struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
-			     unsigned short num, __be32 raddr,
-			     __be32 laddr, int dif);
+			     const struct sk_lookup *params);
 
 int raw_abort(struct sock *sk, int err);
 void raw_icmp_error(struct sk_buff *, int, u32);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index b0bb5d0a30bd..4da5d87a61a5 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -122,15 +122,23 @@ void raw_unhash_sk(struct sock *sk)
 EXPORT_SYMBOL_GPL(raw_unhash_sk);
 
 struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
-		unsigned short num, __be32 raddr, __be32 laddr, int dif)
+			     const struct sk_lookup *params)
 {
+	__be32 raddr = params->saddr.ipv4;
+	__be32 laddr = params->daddr.ipv4;
+
 	sk_for_each_from(sk) {
 		struct inet_sock *inet = inet_sk(sk);
+		bool dev_match;
+
+		dev_match = (!sk->sk_bound_dev_if ||
+				sk->sk_bound_dev_if == params->dif);
 
-		if (net_eq(sock_net(sk), net) && inet->inet_num == num	&&
-		    !(inet->inet_daddr && inet->inet_daddr != raddr) 	&&
+		if (net_eq(sock_net(sk), net) &&
+		    inet->inet_num == params->hnum &&
+		    !(inet->inet_daddr && inet->inet_daddr != raddr) &&
 		    !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
-		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+			dev_match)
 			goto found; /* gotcha */
 	}
 	sk = NULL;
@@ -169,23 +177,20 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
  * RFC 1122: SHOULD pass TOS value up to the transport layer.
  * -> It does. And not only TOS, but all IP header.
  */
-static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
+static int __raw_v4_input(struct sk_buff *skb, const struct iphdr *iph,
+			  struct hlist_head *head)
 {
-	struct sock *sk;
-	struct hlist_head *head;
+	struct net *net = dev_net(skb->dev);
+	const struct sk_lookup params = {
+		.saddr.ipv4 = iph->saddr,
+		.daddr.ipv4 = iph->daddr,
+		.hnum = iph->protocol,
+		.dif  = skb->dev->ifindex,
+	};
 	int delivered = 0;
-	struct net *net;
-
-	read_lock(&raw_v4_hashinfo.lock);
-	head = &raw_v4_hashinfo.ht[hash];
-	if (hlist_empty(head))
-		goto out;
-
-	net = dev_net(skb->dev);
-	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
-			     iph->saddr, iph->daddr,
-			     skb->dev->ifindex);
+	struct sock *sk;
 
+	sk = __raw_v4_lookup(net, __sk_head(head), &params);
 	while (sk) {
 		delivered = 1;
 		if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) &&
@@ -197,11 +202,22 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
 			if (clone)
 				raw_rcv(sk, clone);
 		}
-		sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
-				     iph->saddr, iph->daddr,
-				     skb->dev->ifindex);
+		sk = __raw_v4_lookup(net, sk_next(sk), &params);
 	}
-out:
+
+	return delivered;
+}
+
+static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
+{
+	struct hlist_head *head;
+	int delivered = 0;
+
+	read_lock(&raw_v4_hashinfo.lock);
+	head = &raw_v4_hashinfo.ht[hash];
+	if (!hlist_empty(head))
+		delivered = __raw_v4_input(skb, iph, head);
+
 	read_unlock(&raw_v4_hashinfo.lock);
 	return delivered;
 }
@@ -297,12 +313,18 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
 	read_lock(&raw_v4_hashinfo.lock);
 	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
 	if (raw_sk) {
+		struct sk_lookup params = {
+			.hnum = protocol,
+			.dif = skb->dev->ifindex,
+		};
+
 		iph = (const struct iphdr *)skb->data;
 		net = dev_net(skb->dev);
 
-		while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
-						iph->daddr, iph->saddr,
-						skb->dev->ifindex)) != NULL) {
+		params.saddr.ipv4 = iph->daddr;
+		params.daddr.ipv4 = iph->saddr;
+		while ((raw_sk = __raw_v4_lookup(net, raw_sk,
+						 &params)) != NULL) {
 			raw_err(raw_sk, skb, info);
 			raw_sk = sk_next(raw_sk);
 			iph = (const struct iphdr *)skb->data;
diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c
index e1a51ca68d23..a708de070cc6 100644
--- a/net/ipv4/raw_diag.c
+++ b/net/ipv4/raw_diag.c
@@ -42,11 +42,16 @@ static struct sock *raw_lookup(struct net *net, struct sock *from,
 	struct inet_diag_req_raw *r = (void *)req;
 	struct sock *sk = NULL;
 
-	if (r->sdiag_family == AF_INET)
-		sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
-				     r->id.idiag_dst[0],
-				     r->id.idiag_src[0],
-				     r->id.idiag_if);
+	if (r->sdiag_family == AF_INET) {
+		const struct sk_lookup params = {
+			.saddr.ipv4 = r->id.idiag_dst[0],
+			.daddr.ipv4 = r->id.idiag_src[0],
+			.hnum = r->sdiag_raw_protocol,
+			.dif = r->id.idiag_if,
+		};
+
+		sk = __raw_v4_lookup(net, from, &params);
+	}
 #if IS_ENABLED(CONFIG_IPV6)
 	else
 		sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 03/10] net: ipv4: Convert inet socket lookups to new struct
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Convert the various inet_lookup functions to use the new sk_lookup
struct.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/inet_hashtables.h       | 57 ++++++++++++++--------------------
 net/dccp/ipv4.c                     | 19 +++++++++---
 net/ipv4/inet_diag.c                | 33 ++++++++++++++------
 net/ipv4/inet_hashtables.c          | 48 +++++++++++++++-------------
 net/ipv4/netfilter/nf_socket_ipv4.c |  5 ++-
 net/ipv4/tcp_ipv4.c                 | 62 +++++++++++++++++++++++++++----------
 net/ipv4/udp_diag.c                 |  3 ++
 net/netfilter/xt_TPROXY.c           | 10 +++---
 8 files changed, 142 insertions(+), 95 deletions(-)

diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 5026b1f08bb8..c5f4dc3c06e4 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -218,19 +218,16 @@ void inet_unhash(struct sock *sk);
 struct sock *__inet_lookup_listener(struct net *net,
 				    struct inet_hashinfo *hashinfo,
 				    struct sk_buff *skb, int doff,
-				    const __be32 saddr, const __be16 sport,
-				    const __be32 daddr,
-				    const unsigned short hnum,
-				    const int dif);
+				    struct sk_lookup *params);
 
 static inline struct sock *inet_lookup_listener(struct net *net,
 		struct inet_hashinfo *hashinfo,
 		struct sk_buff *skb, int doff,
-		__be32 saddr, __be16 sport,
-		__be32 daddr, __be16 dport, int dif)
+		struct sk_lookup *params)
 {
-	return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
-				      daddr, ntohs(dport), dif);
+	params->hnum = ntohs(params->dport);
+
+	return __inet_lookup_listener(net, hashinfo, skb, doff, params);
 }
 
 /* Socket demux engine toys. */
@@ -286,53 +283,44 @@ static inline struct sock *inet_lookup_listener(struct net *net,
  */
 struct sock *__inet_lookup_established(struct net *net,
 				       struct inet_hashinfo *hashinfo,
-				       const __be32 saddr, const __be16 sport,
-				       const __be32 daddr, const u16 hnum,
-				       const int dif);
+				       const struct sk_lookup *params);
 
 static inline struct sock *
 	inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo,
-				const __be32 saddr, const __be16 sport,
-				const __be32 daddr, const __be16 dport,
-				const int dif)
+				struct sk_lookup *params)
 {
-	return __inet_lookup_established(net, hashinfo, saddr, sport, daddr,
-					 ntohs(dport), dif);
+	params->hnum = ntohs(params->dport);
+
+	return __inet_lookup_established(net, hashinfo, params);
 }
 
 static inline struct sock *__inet_lookup(struct net *net,
 					 struct inet_hashinfo *hashinfo,
 					 struct sk_buff *skb, int doff,
-					 const __be32 saddr, const __be16 sport,
-					 const __be32 daddr, const __be16 dport,
-					 const int dif,
+					 struct sk_lookup *params,
 					 bool *refcounted)
 {
-	u16 hnum = ntohs(dport);
 	struct sock *sk;
 
-	sk = __inet_lookup_established(net, hashinfo, saddr, sport,
-				       daddr, hnum, dif);
+	params->hnum = ntohs(params->dport);
+
+	sk = __inet_lookup_established(net, hashinfo, params);
 	*refcounted = true;
 	if (sk)
 		return sk;
 	*refcounted = false;
-	return __inet_lookup_listener(net, hashinfo, skb, doff, saddr,
-				      sport, daddr, hnum, dif);
+	return __inet_lookup_listener(net, hashinfo, skb, doff, params);
 }
 
 static inline struct sock *inet_lookup(struct net *net,
 				       struct inet_hashinfo *hashinfo,
 				       struct sk_buff *skb, int doff,
-				       const __be32 saddr, const __be16 sport,
-				       const __be32 daddr, const __be16 dport,
-				       const int dif)
+				       struct sk_lookup *params)
 {
 	struct sock *sk;
 	bool refcounted;
 
-	sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
-			   dport, dif, &refcounted);
+	sk = __inet_lookup(net, hashinfo, skb, doff, params, &refcounted);
 
 	if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt))
 		sk = NULL;
@@ -342,21 +330,22 @@ static inline struct sock *inet_lookup(struct net *net,
 static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
 					     struct sk_buff *skb,
 					     int doff,
-					     const __be16 sport,
-					     const __be16 dport,
+					     struct sk_lookup *params,
 					     bool *refcounted)
 {
 	struct sock *sk = skb_steal_sock(skb);
 	const struct iphdr *iph = ip_hdr(skb);
 
+	params->dif = inet_iif(skb);
+	params->saddr.ipv4 = iph->saddr;
+	params->daddr.ipv4 = iph->daddr;
+
 	*refcounted = true;
 	if (sk)
 		return sk;
 
 	return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb,
-			     doff, iph->saddr, sport,
-			     iph->daddr, dport, inet_iif(skb),
-			     refcounted);
+			     doff, params, refcounted);
 }
 
 u32 inet6_ehashfn(const struct net *net,
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index f85d901f4e3f..f98a65fa5f5e 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -244,6 +244,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
 	__u64 seq;
 	int err;
 	struct net *net = dev_net(skb->dev);
+	struct sk_lookup params = {
+		.saddr.ipv4 = iph->daddr,
+		.daddr.ipv4 = iph->saddr,
+		.dif = inet_iif(skb),
+	};
 
 	/* Only need dccph_dport & dccph_sport which are the first
 	 * 4 bytes in dccp header.
@@ -253,10 +258,11 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
 	BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
 	dh = (struct dccp_hdr *)(skb->data + offset);
 
-	sk = __inet_lookup_established(net, &dccp_hashinfo,
-				       iph->daddr, dh->dccph_dport,
-				       iph->saddr, ntohs(dh->dccph_sport),
-				       inet_iif(skb));
+	params.sport = dh->dccph_dport;
+	params.dport = dh->dccph_sport;
+	params.hnum = ntohs(dh->dccph_sport);
+
+	sk = inet_lookup_established(net, &dccp_hashinfo, &params);
 	if (!sk) {
 		__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
 		return;
@@ -763,6 +769,7 @@ EXPORT_SYMBOL_GPL(dccp_invalid_packet);
 /* this is called when real data arrives */
 static int dccp_v4_rcv(struct sk_buff *skb)
 {
+	struct sk_lookup params = {};
 	const struct dccp_hdr *dh;
 	const struct iphdr *iph;
 	bool refcounted;
@@ -801,9 +808,11 @@ static int dccp_v4_rcv(struct sk_buff *skb)
 				  DCCP_SKB_CB(skb)->dccpd_ack_seq);
 	}
 
+	params.sport = dh->dccph_sport;
+	params.dport = dh->dccph_dport;
 lookup:
 	sk = __inet_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
-			       dh->dccph_sport, dh->dccph_dport, &refcounted);
+			       &params, &refcounted);
 	if (!sk) {
 		dccp_pr_debug("failed to look up flow ID in table and "
 			      "get corresponding socket\n");
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 3828b3a805cd..6c3bc4e408d0 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -396,18 +396,33 @@ struct sock *inet_diag_find_one_icsk(struct net *net,
 	struct sock *sk;
 
 	rcu_read_lock();
-	if (req->sdiag_family == AF_INET)
-		sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[0],
-				 req->id.idiag_dport, req->id.idiag_src[0],
-				 req->id.idiag_sport, req->id.idiag_if);
+	if (req->sdiag_family == AF_INET) {
+		struct sk_lookup params = {
+			.saddr.ipv4 = req->id.idiag_dst[0],
+			.daddr.ipv4 = req->id.idiag_src[0],
+			.sport = req->id.idiag_dport,
+			.dport = req->id.idiag_sport,
+			.hnum = ntohs(req->id.idiag_sport),
+			.dif = req->id.idiag_if,
+		};
+
+		sk = inet_lookup(net, hashinfo, NULL, 0, &params);
+	}
 #if IS_ENABLED(CONFIG_IPV6)
 	else if (req->sdiag_family == AF_INET6) {
 		if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
-		    ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
-			sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[3],
-					 req->id.idiag_dport, req->id.idiag_src[3],
-					 req->id.idiag_sport, req->id.idiag_if);
-		else
+		    ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src)) {
+			struct sk_lookup params = {
+				.saddr.ipv4 = req->id.idiag_dst[3],
+				.daddr.ipv4 = req->id.idiag_src[3],
+				.sport = req->id.idiag_dport,
+				.dport = req->id.idiag_sport,
+				.hnum = ntohs(req->id.idiag_sport),
+				.dif = req->id.idiag_if,
+			};
+
+			sk = inet_lookup(net, hashinfo, NULL, 0, &params);
+		} else
 			sk = inet6_lookup(net, hashinfo, NULL, 0,
 					  (struct in6_addr *)req->id.idiag_dst,
 					  req->id.idiag_dport,
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 2e3389d614d1..5fe9300795b8 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -169,26 +169,28 @@ int __inet_inherit_port(const struct sock *sk, struct sock *child)
 EXPORT_SYMBOL_GPL(__inet_inherit_port);
 
 static inline int compute_score(struct sock *sk, struct net *net,
-				const unsigned short hnum, const __be32 daddr,
-				const int dif, bool exact_dif)
+				const struct sk_lookup *params)
 {
 	int score = -1;
 	struct inet_sock *inet = inet_sk(sk);
 
-	if (net_eq(sock_net(sk), net) && inet->inet_num == hnum &&
-			!ipv6_only_sock(sk)) {
+	if (net_eq(sock_net(sk), net) &&
+	    inet->inet_num == params->hnum &&
+	    !ipv6_only_sock(sk)) {
 		__be32 rcv_saddr = inet->inet_rcv_saddr;
+		int rc;
+
 		score = sk->sk_family == PF_INET ? 2 : 1;
 		if (rcv_saddr) {
-			if (rcv_saddr != daddr)
+			if (rcv_saddr != params->daddr.ipv4)
 				return -1;
 			score += 4;
 		}
-		if (sk->sk_bound_dev_if || exact_dif) {
-			if (sk->sk_bound_dev_if != dif)
-				return -1;
+		rc = sk_lookup_device_cmp(sk, params);
+		if (rc < 0)
+			return -1;
+		if (rc > 0)
 			score += 4;
-		}
 		if (sk->sk_incoming_cpu == raw_smp_processor_id())
 			score++;
 	}
@@ -206,24 +208,25 @@ static inline int compute_score(struct sock *sk, struct net *net,
 struct sock *__inet_lookup_listener(struct net *net,
 				    struct inet_hashinfo *hashinfo,
 				    struct sk_buff *skb, int doff,
-				    const __be32 saddr, __be16 sport,
-				    const __be32 daddr, const unsigned short hnum,
-				    const int dif)
+				    struct sk_lookup *params)
 {
-	unsigned int hash = inet_lhashfn(net, hnum);
+	unsigned int hash = inet_lhashfn(net, params->hnum);
 	struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
 	int score, hiscore = 0, matches = 0, reuseport = 0;
-	bool exact_dif = inet_exact_dif_match(net, skb);
 	struct sock *sk, *result = NULL;
 	u32 phash = 0;
 
+	params->exact_dif = inet_exact_dif_match(net, skb);
+
 	sk_for_each_rcu(sk, &ilb->head) {
-		score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > hiscore) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				phash = inet_ehashfn(net, daddr, hnum,
-						     saddr, sport);
+				phash = inet_ehashfn(net, params->daddr.ipv4,
+						     params->hnum,
+						     params->saddr.ipv4,
+						     params->sport);
 				result = reuseport_select_sock(sk, phash,
 							       skb, doff);
 				if (result)
@@ -265,11 +268,14 @@ void sock_edemux(struct sk_buff *skb)
 EXPORT_SYMBOL(sock_edemux);
 
 struct sock *__inet_lookup_established(struct net *net,
-				  struct inet_hashinfo *hashinfo,
-				  const __be32 saddr, const __be16 sport,
-				  const __be32 daddr, const u16 hnum,
-				  const int dif)
+				       struct inet_hashinfo *hashinfo,
+				       const struct sk_lookup *params)
 {
+	__be32 saddr = params->saddr.ipv4;
+	__be32 daddr = params->daddr.ipv4;
+	__be16 sport = params->sport;
+	u16 hnum = params->hnum;
+	int dif = params->dif;
 	INET_ADDR_COOKIE(acookie, saddr, daddr);
 	const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
 	struct sock *sk;
diff --git a/net/ipv4/netfilter/nf_socket_ipv4.c b/net/ipv4/netfilter/nf_socket_ipv4.c
index 121767b36763..b0f9954712f9 100644
--- a/net/ipv4/netfilter/nf_socket_ipv4.c
+++ b/net/ipv4/netfilter/nf_socket_ipv4.c
@@ -86,14 +86,13 @@ nf_socket_get_sock_v4(struct net *net, struct sk_buff *skb, const int doff,
 		.daddr.ipv4 = daddr,
 		.sport = sport,
 		.dport = dport,
+		.hnum = ntohs(dport),
 		.dif = in->ifindex,
 	};
 
 	switch (protocol) {
 	case IPPROTO_TCP:
-		return inet_lookup(net, &tcp_hashinfo, skb, doff,
-				   saddr, sport, daddr, dport,
-				   in->ifindex);
+		return inet_lookup(net, &tcp_hashinfo, skb, doff, &params);
 	case IPPROTO_UDP:
 		return udp4_lib_lookup(net, &params);
 	}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 3a19ea28339f..a83d1d437abc 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -382,10 +382,16 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
 	u32 delta_us;
 	int err;
 	struct net *net = dev_net(icmp_skb->dev);
-
-	sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr,
-				       th->dest, iph->saddr, ntohs(th->source),
-				       inet_iif(icmp_skb));
+	struct sk_lookup params = {
+		.saddr.ipv4 = iph->daddr,
+		.daddr.ipv4 = iph->saddr,
+		.sport = th->dest,
+		.dport = th->source,
+		.hnum  = ntohs(th->source),
+		.dif   = inet_iif(icmp_skb),
+	};
+
+	sk = inet_lookup_established(net, &tcp_hashinfo, &params);
 	if (!sk) {
 		__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
 		return;
@@ -651,6 +657,15 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
 		key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)
 					&ip_hdr(skb)->saddr, AF_INET);
 	} else if (hash_location) {
+		struct sk_lookup params = {
+			.saddr.ipv4 = ip_hdr(skb)->saddr,
+			.daddr.ipv4 = ip_hdr(skb)->daddr,
+			.sport = th->source,
+			.dport = th->source,
+			.hnum  = ntohs(th->source),
+			.dif   = inet_iif(skb),
+		};
+
 		/*
 		 * active side is lost. Try to find listening socket through
 		 * source port, and then find md5 key through listening socket.
@@ -658,10 +673,8 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
 		 * Incoming packet is checked with md5 hash with finding key,
 		 * no RST generated if md5 hash doesn't match.
 		 */
-		sk1 = __inet_lookup_listener(net, &tcp_hashinfo, NULL, 0,
-					     ip_hdr(skb)->saddr,
-					     th->source, ip_hdr(skb)->daddr,
-					     ntohs(th->source), inet_iif(skb));
+		sk1 = inet_lookup_listener(net, &tcp_hashinfo, NULL, 0,
+					   &params);
 		/* don't send rst if it can't find key */
 		if (!sk1)
 			goto out;
@@ -1509,6 +1522,9 @@ void tcp_v4_early_demux(struct sk_buff *skb)
 	const struct iphdr *iph;
 	const struct tcphdr *th;
 	struct sock *sk;
+	struct sk_lookup params = {
+		.dif = skb->skb_iif,
+	};
 
 	if (skb->pkt_type != PACKET_HOST)
 		return;
@@ -1522,10 +1538,13 @@ void tcp_v4_early_demux(struct sk_buff *skb)
 	if (th->doff < sizeof(struct tcphdr) / 4)
 		return;
 
-	sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
-				       iph->saddr, th->source,
-				       iph->daddr, ntohs(th->dest),
-				       skb->skb_iif);
+	params.saddr.ipv4 = iph->saddr;
+	params.daddr.ipv4 = iph->daddr;
+	params.sport = th->source;
+	params.dport = th->dest;
+	params.hnum  = ntohs(th->dest),
+
+	sk = inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo, &params);
 	if (sk) {
 		skb->sk = sk;
 		skb->destructor = sock_edemux;
@@ -1645,6 +1664,7 @@ EXPORT_SYMBOL(tcp_filter);
 int tcp_v4_rcv(struct sk_buff *skb)
 {
 	struct net *net = dev_net(skb->dev);
+	struct sk_lookup params = { };
 	const struct iphdr *iph;
 	const struct tcphdr *th;
 	bool refcounted;
@@ -1693,9 +1713,11 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
 	TCP_SKB_CB(skb)->sacked	 = 0;
 
+	params.sport = th->source;
+	params.dport = th->dest;
 lookup:
-	sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
-			       th->dest, &refcounted);
+	sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), &params,
+			       &refcounted);
 	if (!sk)
 		goto no_tcp_socket;
 
@@ -1819,12 +1841,18 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	}
 	switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
 	case TCP_TW_SYN: {
+		struct sk_lookup params = {
+			.saddr.ipv4 = iph->saddr,
+			.daddr.ipv4 = iph->daddr,
+			.sport = th->source,
+			.dport = th->dest,
+			.hnum  = ntohs(th->dest),
+			.dif   = inet_iif(skb),
+		};
 		struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
 							&tcp_hashinfo, skb,
 							__tcp_hdrlen(th),
-							iph->saddr, th->source,
-							iph->daddr, th->dest,
-							inet_iif(skb));
+							&params);
 		if (sk2) {
 			inet_twsk_deschedule_put(inet_twsk(sk));
 			sk = sk2;
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 5e0640877536..d7f6af42ebcc 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -47,6 +47,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 			.daddr.ipv4 = req->id.idiag_dst[0],
 			.sport = req->id.idiag_sport,
 			.dport = req->id.idiag_dport,
+			.hnum  = ntohs(req->id.idiag_dport),
 			.dif   =  req->id.idiag_if,
 		};
 
@@ -190,6 +191,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
 			.daddr.ipv4 = req->id.idiag_src[0],
 			.sport = req->id.idiag_dport,
 			.dport = req->id.idiag_sport,
+			.hnum  = ntohs(req->id.idiag_sport),
 			.dif   = req->id.idiag_if,
 		};
 
@@ -204,6 +206,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
 				.daddr.ipv4 = req->id.idiag_src[3],
 				.sport = req->id.idiag_dport,
 				.dport = req->id.idiag_sport,
+				.hnum  = ntohs(req->id.idiag_sport),
 				.dif   = req->id.idiag_if,
 			};
 
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index 972a0e40c59a..5cce7eb7dea2 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -117,6 +117,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
 		.daddr.ipv4 = daddr,
 		.sport = sport,
 		.dport = dport,
+		.hnum  = ntohs(dport),
 		.dif   = in->ifindex,
 	};
 
@@ -129,11 +130,9 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
 		case NFT_LOOKUP_LISTENER:
 			tcph = hp;
 			sk = inet_lookup_listener(net, &tcp_hashinfo, skb,
-						    ip_hdrlen(skb) +
+						  ip_hdrlen(skb) +
 						      __tcp_hdrlen(tcph),
-						    saddr, sport,
-						    daddr, dport,
-						    in->ifindex);
+						  &params);
 
 			if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 				sk = NULL;
@@ -145,8 +144,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
 			break;
 		case NFT_LOOKUP_ESTABLISHED:
 			sk = inet_lookup_established(net, &tcp_hashinfo,
-						    saddr, sport, daddr, dport,
-						    in->ifindex);
+						     &params);
 			break;
 		default:
 			BUG();
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 02/10] net: ipv4: Convert udp socket lookups to new struct
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Convert udp4_lib_lookup and __udp4_lib_lookup to use the new sk_lookup
struct.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/udp.h                   |   6 +-
 net/ipv4/netfilter/nf_socket_ipv4.c |  11 ++-
 net/ipv4/udp.c                      | 170 +++++++++++++++++++-----------------
 net/ipv4/udp_diag.c                 |  51 +++++++----
 net/netfilter/xt_TPROXY.c           |  11 ++-
 5 files changed, 144 insertions(+), 105 deletions(-)

diff --git a/include/net/udp.h b/include/net/udp.h
index 972ce4baab6b..5e0ff095dc6d 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -283,10 +283,8 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
 int udp_lib_setsockopt(struct sock *sk, int level, int optname,
 		       char __user *optval, unsigned int optlen,
 		       int (*push_pending_frames)(struct sock *));
-struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
-			     __be32 daddr, __be16 dport, int dif);
-struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
-			       __be32 daddr, __be16 dport, int dif,
+struct sock *udp4_lib_lookup(struct net *net, struct sk_lookup *params);
+struct sock *__udp4_lib_lookup(struct net *net, struct sk_lookup *params,
 			       struct udp_table *tbl, struct sk_buff *skb);
 struct sock *udp4_lib_lookup_skb(struct sk_buff *skb,
 				 __be16 sport, __be16 dport);
diff --git a/net/ipv4/netfilter/nf_socket_ipv4.c b/net/ipv4/netfilter/nf_socket_ipv4.c
index e9293bdebba0..121767b36763 100644
--- a/net/ipv4/netfilter/nf_socket_ipv4.c
+++ b/net/ipv4/netfilter/nf_socket_ipv4.c
@@ -81,14 +81,21 @@ nf_socket_get_sock_v4(struct net *net, struct sk_buff *skb, const int doff,
 		      const __be16 sport, const __be16 dport,
 		      const struct net_device *in)
 {
+	struct sk_lookup params = {
+		.saddr.ipv4 = saddr,
+		.daddr.ipv4 = daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif = in->ifindex,
+	};
+
 	switch (protocol) {
 	case IPPROTO_TCP:
 		return inet_lookup(net, &tcp_hashinfo, skb, doff,
 				   saddr, sport, daddr, dport,
 				   in->ifindex);
 	case IPPROTO_UDP:
-		return udp4_lib_lookup(net, saddr, sport, daddr, dport,
-				       in->ifindex);
+		return udp4_lib_lookup(net, &params);
 	}
 	return NULL;
 }
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b057653ceca9..132a8f070d16 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -379,15 +379,13 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
 }
 
 static int compute_score(struct sock *sk, struct net *net,
-			 __be32 saddr, __be16 sport,
-			 __be32 daddr, unsigned short hnum, int dif,
-			 bool exact_dif)
+			 const struct sk_lookup *params)
 {
-	int score;
 	struct inet_sock *inet;
+	int score, rc;
 
 	if (!net_eq(sock_net(sk), net) ||
-	    udp_sk(sk)->udp_port_hash != hnum ||
+	    udp_sk(sk)->udp_port_hash != params->hnum ||
 	    ipv6_only_sock(sk))
 		return -1;
 
@@ -395,28 +393,28 @@ static int compute_score(struct sock *sk, struct net *net,
 	inet = inet_sk(sk);
 
 	if (inet->inet_rcv_saddr) {
-		if (inet->inet_rcv_saddr != daddr)
+		if (inet->inet_rcv_saddr != params->daddr.ipv4)
 			return -1;
 		score += 4;
 	}
 
 	if (inet->inet_daddr) {
-		if (inet->inet_daddr != saddr)
+		if (inet->inet_daddr != params->saddr.ipv4)
 			return -1;
 		score += 4;
 	}
 
 	if (inet->inet_dport) {
-		if (inet->inet_dport != sport)
+		if (inet->inet_dport != params->sport)
 			return -1;
 		score += 4;
 	}
 
-	if (sk->sk_bound_dev_if || exact_dif) {
-		if (sk->sk_bound_dev_if != dif)
-			return -1;
+	rc = sk_lookup_device_cmp(sk, params);
+	if (rc < 0)
+		return -1;
+	if (rc > 0)
 		score += 4;
-	}
 	if (sk->sk_incoming_cpu == raw_smp_processor_id())
 		score++;
 	return score;
@@ -436,10 +434,9 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
 
 /* called with rcu_read_lock() */
 static struct sock *udp4_lib_lookup2(struct net *net,
-		__be32 saddr, __be16 sport,
-		__be32 daddr, unsigned int hnum, int dif, bool exact_dif,
-		struct udp_hslot *hslot2,
-		struct sk_buff *skb)
+				     const struct sk_lookup *params,
+				     struct udp_hslot *hslot2,
+				     struct sk_buff *skb)
 {
 	struct sock *sk, *result;
 	int score, badness, matches = 0, reuseport = 0;
@@ -448,13 +445,14 @@ static struct sock *udp4_lib_lookup2(struct net *net,
 	result = NULL;
 	badness = 0;
 	udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-		score = compute_score(sk, net, saddr, sport,
-				      daddr, hnum, dif, exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > badness) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				hash = udp_ehashfn(net, daddr, hnum,
-						   saddr, sport);
+				hash = udp_ehashfn(net, params->daddr.ipv4,
+						   params->hnum,
+						   params->saddr.ipv4,
+						   params->sport);
 				result = reuseport_select_sock(sk, hash, skb,
 							sizeof(struct udphdr));
 				if (result)
@@ -476,28 +474,27 @@ static struct sock *udp4_lib_lookup2(struct net *net,
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
-struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
-		__be16 sport, __be32 daddr, __be16 dport,
-		int dif, struct udp_table *udptable, struct sk_buff *skb)
+struct sock *__udp4_lib_lookup(struct net *net, struct sk_lookup *params,
+			       struct udp_table *udptable, struct sk_buff *skb)
 {
 	struct sock *sk, *result;
-	unsigned short hnum = ntohs(dport);
+	unsigned short hnum = ntohs(params->dport);
 	unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
 	struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-	bool exact_dif = udp_lib_exact_dif_match(net, skb);
 	int score, badness, matches = 0, reuseport = 0;
 	u32 hash = 0;
 
+	params->hnum = hnum;
+	params->exact_dif = udp_lib_exact_dif_match(net, skb);
+
 	if (hslot->count > 10) {
-		hash2 = udp4_portaddr_hash(net, daddr, hnum);
+		hash2 = udp4_portaddr_hash(net, params->daddr.ipv4, hnum);
 		slot2 = hash2 & udptable->mask;
 		hslot2 = &udptable->hash2[slot2];
 		if (hslot->count < hslot2->count)
 			goto begin;
 
-		result = udp4_lib_lookup2(net, saddr, sport,
-					  daddr, hnum, dif,
-					  exact_dif, hslot2, skb);
+		result = udp4_lib_lookup2(net, params, hslot2, skb);
 		if (!result) {
 			unsigned int old_slot2 = slot2;
 			hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
@@ -510,9 +507,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 			if (hslot->count < hslot2->count)
 				goto begin;
 
-			result = udp4_lib_lookup2(net, saddr, sport,
-						  daddr, hnum, dif,
-						  exact_dif, hslot2, skb);
+			result = udp4_lib_lookup2(net, params, hslot2, skb);
 		}
 		return result;
 	}
@@ -520,13 +515,14 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 	result = NULL;
 	badness = 0;
 	sk_for_each_rcu(sk, &hslot->head) {
-		score = compute_score(sk, net, saddr, sport,
-				      daddr, hnum, dif, exact_dif);
+		score = compute_score(sk, net, params);
 		if (score > badness) {
 			reuseport = sk->sk_reuseport;
 			if (reuseport) {
-				hash = udp_ehashfn(net, daddr, hnum,
-						   saddr, sport);
+				hash = udp_ehashfn(net, params->daddr.ipv4,
+						   params->hnum,
+						   params->saddr.ipv4,
+						   params->sport);
 				result = reuseport_select_sock(sk, hash, skb,
 							sizeof(struct udphdr));
 				if (result)
@@ -551,10 +547,16 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
 						 struct udp_table *udptable)
 {
 	const struct iphdr *iph = ip_hdr(skb);
+	struct net *net = dev_net(skb->dev);
+	struct sk_lookup params = {
+		.saddr.ipv4 = iph->saddr,
+		.daddr.ipv4 = iph->daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = inet_iif(skb),
+	};
 
-	return __udp4_lib_lookup(dev_net(skb->dev), iph->saddr, sport,
-				 iph->daddr, dport, inet_iif(skb),
-				 udptable, skb);
+	return __udp4_lib_lookup(net, &params, udptable, skb);
 }
 
 struct sock *udp4_lib_lookup_skb(struct sk_buff *skb,
@@ -570,13 +572,11 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup_skb);
 #if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \
     IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) || \
     IS_ENABLED(CONFIG_NF_SOCKET_IPV4)
-struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
-			     __be32 daddr, __be16 dport, int dif)
+struct sock *udp4_lib_lookup(struct net *net, struct sk_lookup *params)
 {
 	struct sock *sk;
 
-	sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport,
-			       dif, &udp_table, NULL);
+	sk = __udp4_lib_lookup(net, params, &udp_table, NULL);
 	if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 		sk = NULL;
 	return sk;
@@ -585,21 +585,21 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup);
 #endif
 
 static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk,
-				       __be16 loc_port, __be32 loc_addr,
-				       __be16 rmt_port, __be32 rmt_addr,
-				       int dif, unsigned short hnum)
+				       const struct sk_lookup *params)
 {
 	struct inet_sock *inet = inet_sk(sk);
+	__be32 loc_addr = params->daddr.ipv4;
+	__be32 rmt_addr = params->saddr.ipv4;
 
 	if (!net_eq(sock_net(sk), net) ||
-	    udp_sk(sk)->udp_port_hash != hnum ||
+	    udp_sk(sk)->udp_port_hash != params->hnum ||
 	    (inet->inet_daddr && inet->inet_daddr != rmt_addr) ||
-	    (inet->inet_dport != rmt_port && inet->inet_dport) ||
+	    (inet->inet_dport != params->sport && inet->inet_dport) ||
 	    (inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) ||
 	    ipv6_only_sock(sk) ||
-	    (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+	    (sk->sk_bound_dev_if && sk->sk_bound_dev_if != params->dif))
 		return false;
-	if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif))
+	if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, params->dif))
 		return false;
 	return true;
 }
@@ -626,10 +626,15 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
 	int harderr;
 	int err;
 	struct net *net = dev_net(skb->dev);
-
-	sk = __udp4_lib_lookup(net, iph->daddr, uh->dest,
-			iph->saddr, uh->source, skb->dev->ifindex, udptable,
-			NULL);
+	struct sk_lookup params = {
+		.saddr.ipv4 = iph->daddr,
+		.daddr.ipv4 = iph->saddr,
+		.sport = uh->dest,
+		.dport = uh->source,
+		.dif = skb->dev->ifindex,
+	};
+
+	sk = __udp4_lib_lookup(net, &params, udptable, NULL);
 	if (!sk) {
 		__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
 		return;	/* No socket for error */
@@ -1956,9 +1961,16 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum);
 	unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
 	unsigned int offset = offsetof(typeof(*sk), sk_node);
-	int dif = skb->dev->ifindex;
 	struct hlist_node *node;
 	struct sk_buff *nskb;
+	struct sk_lookup params = {
+		.saddr.ipv4 = saddr,
+		.daddr.ipv4 = daddr,
+		.sport = uh->source,
+		.dport = uh->dest,
+		.hnum = hnum,
+		.dif = skb->dev->ifindex,
+	};
 
 	if (use_hash2) {
 		hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
@@ -1970,8 +1982,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	}
 
 	sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) {
-		if (!__udp_is_mcast_sock(net, sk, uh->dest, daddr,
-					 uh->source, saddr, dif, hnum))
+		if (!__udp_is_mcast_sock(net, sk, &params))
 			continue;
 
 		if (!first) {
@@ -2159,13 +2170,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
  * If more than one socket found returns NULL
  */
 static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
-						  __be16 loc_port, __be32 loc_addr,
-						  __be16 rmt_port, __be32 rmt_addr,
-						  int dif)
+						  const struct sk_lookup *params)
 {
 	struct sock *sk, *result;
-	unsigned short hnum = ntohs(loc_port);
-	unsigned int slot = udp_hashfn(net, hnum, udp_table.mask);
+	unsigned int slot = udp_hashfn(net, params->hnum, udp_table.mask);
 	struct udp_hslot *hslot = &udp_table.hash[slot];
 
 	/* Do not bother scanning a too big list */
@@ -2174,8 +2182,7 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
 
 	result = NULL;
 	sk_for_each_rcu(sk, &hslot->head) {
-		if (__udp_is_mcast_sock(net, sk, loc_port, loc_addr,
-					rmt_port, rmt_addr, dif, hnum)) {
+		if (__udp_is_mcast_sock(net, sk, params)) {
 			if (result)
 				return NULL;
 			result = sk;
@@ -2190,21 +2197,20 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
  * if the first socket is an exact match and if not move on.
  */
 static struct sock *__udp4_lib_demux_lookup(struct net *net,
-					    __be16 loc_port, __be32 loc_addr,
-					    __be16 rmt_port, __be32 rmt_addr,
-					    int dif)
+					    const struct sk_lookup *params)
 {
-	unsigned short hnum = ntohs(loc_port);
-	unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum);
+	unsigned int hash2 = udp4_portaddr_hash(net, params->daddr.ipv4,
+						params->hnum);
 	unsigned int slot2 = hash2 & udp_table.mask;
 	struct udp_hslot *hslot2 = &udp_table.hash2[slot2];
-	INET_ADDR_COOKIE(acookie, rmt_addr, loc_addr);
-	const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum);
+	INET_ADDR_COOKIE(acookie, params->saddr.ipv4, params->daddr.ipv4);
+	const __portpair ports = INET_COMBINED_PORTS(params->sport,
+						     params->hnum);
 	struct sock *sk;
 
 	udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-		if (INET_MATCH(sk, net, acookie, rmt_addr,
-			       loc_addr, ports, dif))
+		if (INET_MATCH(sk, net, acookie, params->saddr.ipv4,
+			       params->daddr.ipv4, ports, params->dif))
 			return sk;
 		/* Only check first socket in chain */
 		break;
@@ -2215,11 +2221,13 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net,
 void udp_v4_early_demux(struct sk_buff *skb)
 {
 	struct net *net = dev_net(skb->dev);
+	struct sk_lookup params = {
+		.dif = skb->dev->ifindex,
+	};
 	const struct iphdr *iph;
 	const struct udphdr *uh;
 	struct sock *sk = NULL;
 	struct dst_entry *dst;
-	int dif = skb->dev->ifindex;
 	int ours;
 
 	/* validate the packet */
@@ -2228,6 +2236,11 @@ void udp_v4_early_demux(struct sk_buff *skb)
 
 	iph = ip_hdr(skb);
 	uh = udp_hdr(skb);
+	params.saddr.ipv4 = iph->saddr;
+	params.daddr.ipv4 = iph->daddr;
+	params.sport = uh->source;
+	params.dport = uh->dest;
+	params.hnum = ntohs(uh->dest);
 
 	if (skb->pkt_type == PACKET_BROADCAST ||
 	    skb->pkt_type == PACKET_MULTICAST) {
@@ -2244,12 +2257,9 @@ void udp_v4_early_demux(struct sk_buff *skb)
 				return;
 		}
 
-		sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
-						   uh->source, iph->saddr, dif);
-	} else if (skb->pkt_type == PACKET_HOST) {
-		sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr,
-					     uh->source, iph->saddr, dif);
-	}
+		sk = __udp4_lib_mcast_demux_lookup(net, &params);
+	} else if (skb->pkt_type == PACKET_HOST)
+		sk = __udp4_lib_demux_lookup(net, &params);
 
 	if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
 		return;
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 4515836d2a3a..5e0640877536 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -41,11 +41,17 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 	struct net *net = sock_net(in_skb->sk);
 
 	rcu_read_lock();
-	if (req->sdiag_family == AF_INET)
-		sk = __udp4_lib_lookup(net,
-				req->id.idiag_src[0], req->id.idiag_sport,
-				req->id.idiag_dst[0], req->id.idiag_dport,
-				req->id.idiag_if, tbl, NULL);
+	if (req->sdiag_family == AF_INET) {
+		struct sk_lookup params = {
+			.saddr.ipv4 = req->id.idiag_src[0],
+			.daddr.ipv4 = req->id.idiag_dst[0],
+			.sport = req->id.idiag_sport,
+			.dport = req->id.idiag_dport,
+			.dif   =  req->id.idiag_if,
+		};
+
+		sk = __udp4_lib_lookup(net, &params, tbl, NULL);
+	}
 #if IS_ENABLED(CONFIG_IPV6)
 	else if (req->sdiag_family == AF_INET6)
 		sk = __udp6_lib_lookup(net,
@@ -178,27 +184,38 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
 
 	rcu_read_lock();
 
-	if (req->sdiag_family == AF_INET)
-		sk = __udp4_lib_lookup(net,
-				req->id.idiag_dst[0], req->id.idiag_dport,
-				req->id.idiag_src[0], req->id.idiag_sport,
-				req->id.idiag_if, tbl, NULL);
+	if (req->sdiag_family == AF_INET) {
+		struct sk_lookup params = {
+			.saddr.ipv4 = req->id.idiag_dst[0],
+			.daddr.ipv4 = req->id.idiag_src[0],
+			.sport = req->id.idiag_dport,
+			.dport = req->id.idiag_sport,
+			.dif   = req->id.idiag_if,
+		};
+
+		sk = __udp4_lib_lookup(net, &params, tbl, NULL);
+	}
 #if IS_ENABLED(CONFIG_IPV6)
 	else if (req->sdiag_family == AF_INET6) {
 		if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
-		    ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
-			sk = __udp4_lib_lookup(net,
-					req->id.idiag_dst[3], req->id.idiag_dport,
-					req->id.idiag_src[3], req->id.idiag_sport,
-					req->id.idiag_if, tbl, NULL);
-
-		else
+		    ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src)) {
+			struct sk_lookup params = {
+				.saddr.ipv4 = req->id.idiag_dst[3],
+				.daddr.ipv4 = req->id.idiag_src[3],
+				.sport = req->id.idiag_dport,
+				.dport = req->id.idiag_sport,
+				.dif   = req->id.idiag_if,
+			};
+
+			sk = __udp4_lib_lookup(net, &params, tbl, NULL);
+		} else {
 			sk = __udp6_lib_lookup(net,
 					(struct in6_addr *)req->id.idiag_dst,
 					req->id.idiag_dport,
 					(struct in6_addr *)req->id.idiag_src,
 					req->id.idiag_sport,
 					req->id.idiag_if, tbl, NULL);
+		}
 	}
 #endif
 	else {
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index d767e35fff6b..972a0e40c59a 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -112,6 +112,14 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
 		      const struct net_device *in,
 		      const enum nf_tproxy_lookup_t lookup_type)
 {
+	struct sk_lookup params = {
+		.saddr.ipv4 = saddr,
+		.daddr.ipv4 = daddr,
+		.sport = sport,
+		.dport = dport,
+		.dif   = in->ifindex,
+	};
+
 	struct sock *sk;
 	struct tcphdr *tcph;
 
@@ -145,8 +153,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
 		}
 		break;
 	case IPPROTO_UDP:
-		sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
-				     in->ifindex);
+		sk = udp4_lib_lookup(net, &params);
 		if (sk) {
 			int connected = (sk->sk_state == TCP_ESTABLISHED);
 			int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0);
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 01/10] net: Add sk_lookup struct and helper
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern
In-Reply-To: <1501557206-27503-1-git-send-email-dsahern@gmail.com>

Consolidate the socket lookup args into a struct.

Add helper that compares sk_bound_dev_if for a socket to the lookup
parameters.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 include/net/sock.h | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/include/net/sock.h b/include/net/sock.h
index 7c0632c7e870..a2db5fd30192 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -491,6 +491,44 @@ enum sk_pacing {
 #define rcu_dereference_sk_user_data(sk)	rcu_dereference(__sk_user_data((sk)))
 #define rcu_assign_sk_user_data(sk, ptr)	rcu_assign_pointer(__sk_user_data((sk)), ptr)
 
+/* used for socket lookups */
+struct sk_lookup {
+	union {
+		const struct in6_addr *ipv6;
+		__be32 ipv4;
+	} saddr;
+	union {
+		const struct in6_addr *ipv6;
+		__be32 ipv4;
+	} daddr;
+
+	__be16 sport;
+	__be16 dport;
+	unsigned short hnum;
+
+	int dif;
+	bool exact_dif;
+};
+
+/* Compare sk_bound_dev_if to socket lookup dif
+ * Returns:
+ *   -1   exact dif required and not met
+ *    0   sk_bound_dev_if is either not set or does not match
+ *    1   sk_bound_dev_if is set and matches dif
+ */
+static inline int sk_lookup_device_cmp(const struct sock *sk,
+				       const struct sk_lookup *params)
+{
+	/* exact_dif true == l3mdev case */
+	if (params->exact_dif && sk->sk_bound_dev_if != params->dif)
+		return -1;
+
+	if (sk->sk_bound_dev_if && sk->sk_bound_dev_if == params->dif)
+		return 1;
+
+	return 0;
+}
+
 /*
  * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK
  * or not whether his port will be reused by someone else. SK_FORCE_REUSE
-- 
2.1.4

^ permalink raw reply related

* [PATCH net-next 00/10] net: l3mdev: Support for sockets bound to enslaved device
From: David Ahern @ 2017-08-01  3:13 UTC (permalink / raw)
  To: netdev; +Cc: David Ahern

A missing piece to the VRF puzzle is the ability to bind sockets to
devices enslaved to a VRF. This patch set adds the enslaved device
index, sdif, to IPv4 and IPv6 socket lookups. The end result for users
is the following scope options for services:

1. "global" services - sockets not bound to any device

   Allows 1 service to work across all network interfaces with
   connected sockets bound to the VRF the connection originates
   (Requires net.ipv4.tcp_l3mdev_accept=1 for TCP and
    net.ipv4.udp_l3mdev_accept=1 for UDP)

2. "VRF" local services - sockets bound to a VRF

   Sockets work across all network interfaces enslaved to a VRF but
   are limited to just the one VRF.

3. "device" services - sockets bound to a specific network interface

   Service works only through the one specific interface.

Existing code for socket lookups already pass in 6+ arguments. Rather
than add another for the enslaved device index, the existing lookups
are converted to use a new sk_lookup struct. From there, the enslaved
device index becomes another element of the struct.

Patch 1 introduces sk_lookup struct and helper.

Patches 2-4 convert udp, inet and socket lookups for IPv4 to use the
new sk_lookup struct. Meant to be a conversion of IPv4 code only; no
functional change intended.

Patches 5-7 convert udp, inet and socket lookups for IPv6 to use the
new sk_lookup struct. Meant to be a conversion of IPv6 code only; no
functional change intended.

Patch 8 adds sdif to the sk_lookup struct allowing lookups to consider
a second device index.

Patches 9-10 add support for the enslaved device index to ipv4 and ipv6
socket lookups.

Changes since RFC:
- no significant logic changes; mainly whitespace cleanups

David Ahern (10):
  net: Add sk_lookup struct and helper
  net: ipv4: Convert udp socket lookups to new struct
  net: ipv4: Convert inet socket lookups to new struct
  net: ipv4: Convert raw sockets to sk_lookup
  net: ipv6: Convert udp socket lookups to new struct
  net: ipv6: Convert inet socket lookups to new struct
  net: ipv6: Convert raw sockets to sk_lookup
  net: Add sdif to sk_lookup
  net: ipv4: Support for sockets bound to enslaved device
  net: ipv6: Support for sockets bound to enslaved device

 include/linux/igmp.h                |   3 +-
 include/linux/ipv6.h                |   8 ++
 include/net/inet6_hashtables.h      |  44 ++++-----
 include/net/inet_hashtables.h       |  67 ++++++-------
 include/net/ip.h                    |  10 ++
 include/net/raw.h                   |   3 +-
 include/net/rawv6.h                 |   3 +-
 include/net/sock.h                  |  42 +++++++++
 include/net/tcp.h                   |  17 ++++
 include/net/udp.h                   |  18 +---
 net/dccp/ipv4.c                     |  19 +++-
 net/dccp/ipv6.c                     |  22 +++--
 net/ipv4/igmp.c                     |   6 +-
 net/ipv4/inet_diag.c                |  50 +++++++---
 net/ipv4/inet_hashtables.c          |  59 +++++++-----
 net/ipv4/netfilter/nf_socket_ipv4.c |  16 +++-
 net/ipv4/raw.c                      |  77 +++++++++------
 net/ipv4/raw_diag.c                 |  30 ++++--
 net/ipv4/tcp_ipv4.c                 |  64 +++++++++----
 net/ipv4/udp.c                      | 175 ++++++++++++++++++----------------
 net/ipv4/udp_diag.c                 |  89 ++++++++++++------
 net/ipv6/inet6_hashtables.c         |  75 ++++++++-------
 net/ipv6/netfilter/nf_socket_ipv6.c |  16 +++-
 net/ipv6/raw.c                      |  44 +++++----
 net/ipv6/tcp_ipv6.c                 |  63 +++++++++----
 net/ipv6/udp.c                      | 181 ++++++++++++++++++++----------------
 net/netfilter/xt_TPROXY.c           |  39 +++++---
 27 files changed, 759 insertions(+), 481 deletions(-)

-- 
2.1.4

^ permalink raw reply

* Re: [PATCH V3 net-next] TLP: Don't reschedule PTO when there's one outstanding TLP retransmission
From: Neal Cardwell @ 2017-08-01  3:04 UTC (permalink / raw)
  To: maowenan
  Cc: Netdev, David Miller, Yuchung Cheng, Nandita Dukkipati,
	weiyongjun (A), Chenweilong, Wangkefeng (Kevin)
In-Reply-To: <CADVnQymVniXHxEDW8aA8z+M=G_qNfo+jJfUBrfHycM4-voiDJw@mail.gmail.com>

On Mon, Jul 31, 2017 at 11:49 AM, Neal Cardwell <ncardwell@google.com> wrote:
> On Sun, Jul 30, 2017 at 11:29 PM, maowenan <maowenan@huawei.com> wrote:
>> [Mao Wenan]please refer to the attachment, test.pkt is packetdrill script.
>> In test.pcap, packet number 17 is the TLP probe, packet number 218 is the
>> retransmission packet because client don't send data packet to server.
>> From the capture time, there are about 6 seconds the retransmission
>> packet can be sent, and this time can be added more as long as client
>> send data packet continually.
>> I have reproduced this issue in Linux 4.13-rc3, 3.10, 4.1. Please check the timing
>> When you use test.pkt to reproduce in your environment.
>
> Thank you for your very nice packetdrill test case illustrating this
> problem! And thanks for verifying that the problem shows up in those
> kernel versions.
>
> We are able to run the script in our environment and both verify that
> the bug is the one we hypothesized, and verify our  proposed patch
> fixes it (the RTO for the TLP happens 221ms after the TLP, instead of
> ~5 secs later). We will send out our proposed patches ASAP.

The timer patches are upstream for review for the "net" branch:

  https://patchwork.ozlabs.org/patch/796057/
  https://patchwork.ozlabs.org/patch/796058/
  https://patchwork.ozlabs.org/patch/796059/

Again, thank you for reporting this and providing a packetdrill script
to reproduce this!

neal

^ permalink raw reply

* [PATCH net 3/3] tcp: fix xmit timer to only be reset if data ACKed/SACKed
From: Neal Cardwell @ 2017-08-01  2:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Neal Cardwell, Yuchung Cheng, Nandita Dukkipati
In-Reply-To: <20170801025814.31206-1-ncardwell@google.com>

Fix a TCP loss recovery performance bug raised recently on the netdev
list, in two threads:

(i)  July 26, 2017: netdev thread "TCP fast retransmit issues"
(ii) July 26, 2017: netdev thread:
     "[PATCH V2 net-next] TLP: Don't reschedule PTO when there's one
     outstanding TLP retransmission"

The basic problem is that incoming TCP packets that did not indicate
forward progress could cause the xmit timer (TLP or RTO) to be rearmed
and pushed back in time. In certain corner cases this could result in
the following problems noted in these threads:

 - Repeated ACKs coming in with bogus SACKs corrupted by middleboxes
   could cause TCP to repeatedly schedule TLPs forever. We kept
   sending TLPs after every ~200ms, which elicited bogus SACKs, which
   caused more TLPs, ad infinitum; we never fired an RTO to fill in
   the holes.

 - Incoming data segments could, in some cases, cause us to reschedule
   our RTO or TLP timer further out in time, for no good reason. This
   could cause repeated inbound data to result in stalls in outbound
   data, in the presence of packet loss.

This commit fixes these bugs by changing the TLP and RTO ACK
processing to:

 (a) Only reschedule the xmit timer once per ACK.

 (b) Only reschedule the xmit timer if tcp_clean_rtx_queue() deems the
     ACK indicates sufficient forward progress (a packet was
     cumulatively ACKed, or we got a SACK for a packet that was sent
     before the most recent retransmit of the write queue head).

This brings us back into closer compliance with the RFCs, since, as
the comment for tcp_rearm_rto() notes, we should only restart the RTO
timer after forward progress on the connection. Previously we were
restarting the xmit timer even in these cases where there was no
forward progress.

As a side benefit, this commit simplifies and speeds up the TCP timer
arming logic. We had been calling inet_csk_reset_xmit_timer() three
times on normal ACKs that cumulatively acknowledged some data:

1) Once near the top of tcp_ack() to switch from TLP timer to RTO:
        if (icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)
               tcp_rearm_rto(sk);

2) Once in tcp_clean_rtx_queue(), to update the RTO:
        if (flag & FLAG_ACKED) {
               tcp_rearm_rto(sk);

3) Once in tcp_ack() after tcp_fastretrans_alert() to switch from RTO
   to TLP:
        if (icsk->icsk_pending == ICSK_TIME_RETRANS)
               tcp_schedule_loss_probe(sk);

This commit, by only rescheduling the xmit timer once per ACK,
simplifies the code and reduces CPU overhead.

This commit was tested in an A/B test with Google web server
traffic. SNMP stats and request latency metrics were within noise
levels, substantiating that for normal web traffic patterns this is a
rare issue. This commit was also tested with packetdrill tests to
verify that it fixes the timer behavior in the corner cases discussed
in the netdev threads mentioned above.

This patch is a bug fix patch intended to be queued for -stable
relases.

Fixes: 6ba8a3b19e76 ("tcp: Tail loss probe (TLP)")
Reported-by: Klavs Klavsen <kl@vsen.dk>
Reported-by: Mao Wenan <maowenan@huawei.com>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Nandita Dukkipati <nanditad@google.com>
---
 net/ipv4/tcp_input.c  | 25 ++++++++++++++++---------
 net/ipv4/tcp_output.c |  9 ---------
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 345febf0a46e..3e777cfbba56 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -107,6 +107,7 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2;
 #define FLAG_ORIG_SACK_ACKED	0x200 /* Never retransmitted data are (s)acked	*/
 #define FLAG_SND_UNA_ADVANCED	0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */
 #define FLAG_DSACKING_ACK	0x800 /* SACK blocks contained D-SACK info */
+#define FLAG_SET_XMIT_TIMER	0x1000 /* Set TLP or RTO timer */
 #define FLAG_SACK_RENEGING	0x2000 /* snd_una advanced to a sacked seq */
 #define FLAG_UPDATE_TS_RECENT	0x4000 /* tcp_replace_ts_recent() */
 #define FLAG_NO_CHALLENGE_ACK	0x8000 /* do not call tcp_send_challenge_ack()	*/
@@ -3016,6 +3017,13 @@ void tcp_rearm_rto(struct sock *sk)
 	}
 }
 
+/* Try to schedule a loss probe; if that doesn't work, then schedule an RTO. */
+static void tcp_set_xmit_timer(struct sock *sk)
+{
+	if (!tcp_schedule_loss_probe(sk))
+		tcp_rearm_rto(sk);
+}
+
 /* If we get here, the whole TSO packet has not been acked. */
 static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb)
 {
@@ -3177,7 +3185,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 					ca_rtt_us, sack->rate);
 
 	if (flag & FLAG_ACKED) {
-		tcp_rearm_rto(sk);
+		flag |= FLAG_SET_XMIT_TIMER;  /* set TLP or RTO timer */
 		if (unlikely(icsk->icsk_mtup.probe_size &&
 			     !after(tp->mtu_probe.probe_seq_end, tp->snd_una))) {
 			tcp_mtup_probe_success(sk);
@@ -3205,7 +3213,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 		 * after when the head was last (re)transmitted. Otherwise the
 		 * timeout may continue to extend in loss recovery.
 		 */
-		tcp_rearm_rto(sk);
+		flag |= FLAG_SET_XMIT_TIMER;  /* set TLP or RTO timer */
 	}
 
 	if (icsk->icsk_ca_ops->pkts_acked) {
@@ -3577,9 +3585,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 	if (after(ack, tp->snd_nxt))
 		goto invalid_ack;
 
-	if (icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)
-		tcp_rearm_rto(sk);
-
 	if (after(ack, prior_snd_una)) {
 		flag |= FLAG_SND_UNA_ADVANCED;
 		icsk->icsk_retransmits = 0;
@@ -3644,18 +3649,20 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 	flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked,
 				    &sack_state);
 
+	if (tp->tlp_high_seq)
+		tcp_process_tlp_ack(sk, ack, flag);
+	/* If needed, reset TLP/RTO timer; RACK may later override this. */
+	if (flag & FLAG_SET_XMIT_TIMER)
+		tcp_set_xmit_timer(sk);
+
 	if (tcp_ack_is_dubious(sk, flag)) {
 		is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
 		tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit);
 	}
-	if (tp->tlp_high_seq)
-		tcp_process_tlp_ack(sk, ack, flag);
 
 	if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
 		sk_dst_confirm(sk);
 
-	if (icsk->icsk_pending == ICSK_TIME_RETRANS)
-		tcp_schedule_loss_probe(sk);
 	delivered = tp->delivered - delivered;	/* freshly ACKed or SACKed */
 	lost = tp->lost - lost;			/* freshly marked lost */
 	tcp_rate_gen(sk, delivered, lost, sack_state.rate);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 0ae6b5d176c0..c99cba897b9c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2380,21 +2380,12 @@ bool tcp_schedule_loss_probe(struct sock *sk)
 	u32 rtt = usecs_to_jiffies(tp->srtt_us >> 3);
 	u32 timeout, rto_delta_us;
 
-	/* No consecutive loss probes. */
-	if (WARN_ON(icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)) {
-		tcp_rearm_rto(sk);
-		return false;
-	}
 	/* Don't do any loss probe on a Fast Open connection before 3WHS
 	 * finishes.
 	 */
 	if (tp->fastopen_rsk)
 		return false;
 
-	/* TLP is only scheduled when next timer event is RTO. */
-	if (icsk->icsk_pending != ICSK_TIME_RETRANS)
-		return false;
-
 	/* Schedule a loss probe in 2*RTT for SACK capable connections
 	 * in Open state, that are either limited by cwnd or application.
 	 */
-- 
2.14.0.rc0.400.g1c36432dff-goog

^ permalink raw reply related

* [PATCH net 2/3] tcp: enable xmit timer fix by having TLP use time when RTO should fire
From: Neal Cardwell @ 2017-08-01  2:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Neal Cardwell, Yuchung Cheng, Nandita Dukkipati
In-Reply-To: <20170801025814.31206-1-ncardwell@google.com>

Have tcp_schedule_loss_probe() base the TLP scheduling decision based
on when the RTO *should* fire. This is to enable the upcoming xmit
timer fix in this series, where tcp_schedule_loss_probe() cannot
assume that the last timer installed was an RTO timer (because we are
no longer doing the "rearm RTO, rearm RTO, rearm TLP" dance on every
ACK). So tcp_schedule_loss_probe() must independently figure out when
an RTO would want to fire.

In the new TLP implementation following in this series, we cannot
assume that icsk_timeout was set based on an RTO; after processing a
cumulative ACK the icsk_timeout we see can be from a previous TLP or
RTO. So we need to independently recalculate the RTO time (instead of
reading it out of icsk_timeout). Removing this dependency on the
nature of icsk_timeout makes things a little easier to reason about
anyway.

Note that the old and new code should be equivalent, since they are
both saying: "if the RTO is in the future, but at an earlier time than
the normal TLP time, then set the TLP timer to fire when the RTO would
have fired".

Fixes: 6ba8a3b19e76 ("tcp: Tail loss probe (TLP)")
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Nandita Dukkipati <nanditad@google.com>
---
 net/ipv4/tcp_output.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 2f1588bf73da..0ae6b5d176c0 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2377,8 +2377,8 @@ bool tcp_schedule_loss_probe(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
-	u32 timeout, tlp_time_stamp, rto_time_stamp;
 	u32 rtt = usecs_to_jiffies(tp->srtt_us >> 3);
+	u32 timeout, rto_delta_us;
 
 	/* No consecutive loss probes. */
 	if (WARN_ON(icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)) {
@@ -2418,13 +2418,9 @@ bool tcp_schedule_loss_probe(struct sock *sk)
 	timeout = max_t(u32, timeout, msecs_to_jiffies(10));
 
 	/* If RTO is shorter, just schedule TLP in its place. */
-	tlp_time_stamp = tcp_jiffies32 + timeout;
-	rto_time_stamp = (u32)inet_csk(sk)->icsk_timeout;
-	if ((s32)(tlp_time_stamp - rto_time_stamp) > 0) {
-		s32 delta = rto_time_stamp - tcp_jiffies32;
-		if (delta > 0)
-			timeout = delta;
-	}
+	rto_delta_us = tcp_rto_delta_us(sk);  /* How far in future is RTO? */
+	if (rto_delta_us > 0)
+		timeout = min_t(u32, timeout, usecs_to_jiffies(rto_delta_us));
 
 	inet_csk_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout,
 				  TCP_RTO_MAX);
-- 
2.14.0.rc0.400.g1c36432dff-goog

^ permalink raw reply related

* [PATCH net 1/3] tcp: introduce tcp_rto_delta_us() helper for xmit timer fix
From: Neal Cardwell @ 2017-08-01  2:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Neal Cardwell, Yuchung Cheng, Nandita Dukkipati
In-Reply-To: <20170801025814.31206-1-ncardwell@google.com>

Pure refactor. This helper will be required in the xmit timer fix
later in the patch series. (Because the TLP logic will want to make
this calculation.)

Fixes: 6ba8a3b19e76 ("tcp: Tail loss probe (TLP)")
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Signed-off-by: Nandita Dukkipati <nanditad@google.com>
---
 include/net/tcp.h    | 10 ++++++++++
 net/ipv4/tcp_input.c |  5 +----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 70483296157f..ada65e767b28 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1916,6 +1916,16 @@ extern void tcp_rack_advance(struct tcp_sock *tp, u8 sacked, u32 end_seq,
 			     u64 xmit_time);
 extern void tcp_rack_reo_timeout(struct sock *sk);
 
+/* At how many usecs into the future should the RTO fire? */
+static inline s64 tcp_rto_delta_us(const struct sock *sk)
+{
+	const struct sk_buff *skb = tcp_write_queue_head(sk);
+	u32 rto = inet_csk(sk)->icsk_rto;
+	u64 rto_time_stamp_us = skb->skb_mstamp + jiffies_to_usecs(rto);
+
+	return rto_time_stamp_us - tcp_sk(sk)->tcp_mstamp;
+}
+
 /*
  * Save and compile IPv4 options, return a pointer to it
  */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2920e0cb09f8..345febf0a46e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3004,10 +3004,7 @@ void tcp_rearm_rto(struct sock *sk)
 		/* Offset the time elapsed after installing regular RTO */
 		if (icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT ||
 		    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
-			struct sk_buff *skb = tcp_write_queue_head(sk);
-			u64 rto_time_stamp = skb->skb_mstamp +
-					     jiffies_to_usecs(rto);
-			s64 delta_us = rto_time_stamp - tp->tcp_mstamp;
+			s64 delta_us = tcp_rto_delta_us(sk);
 			/* delta_us may not be positive if the socket is locked
 			 * when the retrans timer fires and is rescheduled.
 			 */
-- 
2.14.0.rc0.400.g1c36432dff-goog

^ permalink raw reply related

* [PATCH net 0/3] tcp: fix xmit timer rearming to avoid stalls
From: Neal Cardwell @ 2017-08-01  2:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Neal Cardwell

This patch series is a bug fix for a TCP loss recovery performance bug
reported independently in recent netdev threads:
    
 (i)  July 26, 2017: netdev thread "TCP fast retransmit issues"
 (ii) July 26, 2017: netdev thread:
       "[PATCH V2 net-next] TLP: Don't reschedule PTO when there's one
       outstanding TLP retransmission"

Many thanks to Klavs Klavsen and Mao Wenan for the detailed reports,
traces, and packetdrill test cases, which enabled us to root-cause
this issue and verify the fix.

Neal Cardwell (3):
  tcp: introduce tcp_rto_delta_us() helper for xmit timer fix
  tcp: enable xmit timer fix by having TLP use time when RTO should fire
  tcp: fix xmit timer to only be reset if data ACKed/SACKed

 include/net/tcp.h     | 10 ++++++++++
 net/ipv4/tcp_input.c  | 30 +++++++++++++++++-------------
 net/ipv4/tcp_output.c | 21 ++++-----------------
 3 files changed, 31 insertions(+), 30 deletions(-)

-- 
2.14.0.rc0.400.g1c36432dff-goog

^ permalink raw reply

* Re: [RFC net-next] net ipv6: convert fib6_table rwlock to a percpu lock
From: Shaohua Li @ 2017-08-01  2:57 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, davem, Kernel-team, Shaohua Li, Wei Wang
In-Reply-To: <20170731161007.61c2d958@xeon-e3>

On Mon, Jul 31, 2017 at 04:10:07PM -0700, Stephen Hemminger wrote:
> On Mon, 31 Jul 2017 10:18:57 -0700
> Shaohua Li <shli@kernel.org> wrote:
> 
> > From: Shaohua Li <shli@fb.com>
> > 
> > In a syn flooding test, the fib6_table rwlock is a significant
> > bottleneck. While converting the rwlock to rcu sounds straighforward,
> > but is very challenging if it's possible. A percpu spinlock is quite
> > trival for this problem since updating the routing table is a rare
> > event. In my test, the server receives around 1.5 Mpps in syn flooding
> > test without the patch in a dual sockets and 56-CPU system. With the
> > patch, the server receives around 3.8Mpps, and perf report doesn't show
> > the locking issue.
> > 
> > Cc: Wei Wang <weiwan@google.com>
> 
> You just reinvented brlock...

you mean lglock? It has been removed from kernel.
 
> RCU is not that hard, why not do it right?

Maybe. But don't think it's the reason why we shouldn't do the percpu lock now,
this is a simple change, if some smart guys find a way of RCU, we can easily
remove this.

^ permalink raw reply

* Re: [PATCH net] ipv6: set fc_protocol with 0 when rtm_protocol is RTPROT_REDIRECT
From: Xin Long @ 2017-08-01  2:50 UTC (permalink / raw)
  To: David Ahern; +Cc: network dev, davem, Mantas Mikulėnas
In-Reply-To: <b0edcf05-9ce4-94d4-3662-767e6ff86843@gmail.com>

On Tue, Aug 1, 2017 at 2:01 PM, David Ahern <dsahern@gmail.com> wrote:
> On 7/31/17 7:40 PM, Xin Long wrote:
>> To respect the old code more, setting RTPROT_RA only when
>> it's with the flag (ADDRCONF | DEFAULT | ROUTEINFO),
>> shouldn't it be:
>
> Look at rtm_fill_info:
>
>         if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
>                         rtm->rtm_protocol = RTPROT_RA;
>
>
> If either flag is set the protocol should be RTPROT_RA and looking at
> both places that seems correct to me.
>
ok, right

^ permalink raw reply

* Re: [PATCH V2 net-next 0/2] liquidio: Add support for managing liquidio adapter
From: Felix Manlunas @ 2017-08-01  2:09 UTC (permalink / raw)
  To: David Miller
  Cc: simon.horman, netdev, raghu.vatsavayi, derek.chickles,
	satananda.burla, veerasenareddy.burru, jakub.kicinski
In-Reply-To: <20170731.175937.1373949013417491840.davem@davemloft.net>

On Mon, Jul 31, 2017 at 05:59:37PM -0700, David Miller wrote:
> From: Simon Horman <simon.horman@netronome.com>
> Date: Sun, 30 Jul 2017 22:21:04 +0200
> 
> > On Fri, Jul 28, 2017 at 11:17:07PM -0700, Felix Manlunas wrote:
> >> From: Veerasenareddy Burru <veerasenareddy.burru@cavium.com>
> >> 
> >> The LiquidIO adapter has processor cores that can run Linux. This patch
> >> set adds support to create a virtual Ethernet interface on host to
> >> communicate with applications running on Linux in the LiquidIO adapter.
> >> The virtual Ethernet interface also provides login access to Linux on
> >> LiquidIO through ssh for management and debugging.
> > 
> > As per the somewhat more detailed feedback provided by my colleague Jakub
> > Kicinski to v1 of this patchset[1] I am concerned that this patchset breaks down
> > the long standing practice of not granting direct access to firmware from
> > userspace.
> > 
> > [1] https://www.spinics.net/lists/netdev/msg444929.html
> 
> Agreed, I've seen no attempt to address this important feedback, which
> I agree with.

We posted a response to the original comment on Friday 28-July.
but for some reason, it did not make to the mailing list outside
cavium domain. our apologies, we did not double check before submitting
V2 patch. Please find below the response reposted on original thread

http://marc.info/?l=linux-netdev&m=150155273724386&w=2

^ permalink raw reply

* Re: [PATCH net] ipv6: set fc_protocol with 0 when rtm_protocol is RTPROT_REDIRECT
From: David Ahern @ 2017-08-01  2:01 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, davem, Mantas Mikulėnas
In-Reply-To: <CADvbK_dWwZU1EXf4ehAyV9cWOK-7b4hn=mGrytGTYACrCUUQ6g@mail.gmail.com>

On 7/31/17 7:40 PM, Xin Long wrote:
> To respect the old code more, setting RTPROT_RA only when
> it's with the flag (ADDRCONF | DEFAULT | ROUTEINFO),
> shouldn't it be:

Look at rtm_fill_info:

	if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
                        rtm->rtm_protocol = RTPROT_RA;


If either flag is set the protocol should be RTPROT_RA and looking at
both places that seems correct to me.

^ permalink raw reply

* Re: [PATCH net-next 2/2] liquidio: Add support to create management interface
From: Felix Manlunas @ 2017-08-01  1:58 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, raghu.vatsavayi, derek.chickles, satananda.burla,
	veerasenareddy.burru
In-Reply-To: <20170718115827.7bd737f2@cakuba.netronome.com>

On Tue, Jul 18, 2017 at 11:58:27AM -0700, Jakub Kicinski wrote:
> On Mon, 17 Jul 2017 12:52:17 -0700, Felix Manlunas wrote:
> > From: VSR Burru <veerasenareddy.burru@cavium.com>
> > 
> > This patch adds support to create a virtual ethernet interface to
> > communicate with Linux on LiquidIO adapter for management.
> > 
> > Signed-off-by: VSR Burru <veerasenareddy.burru@cavium.com>
> > Signed-off-by: Srinivasa Jampala <Srinivasa.Jampala@cavium.com>
> > Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
> > Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@cavium.com>
> > Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
> 
> Not my call, but I have mixed feelings about this one.  Is there any
> precedent under drivers/net/ethernet of exposing special communication
> channels with FW like this?  It's irrelevant to me that you're running
> SSH, arbitrary communication with FW from userspace is not something
> netdev community usually accepts.  And I'm afraid what the effects will
> be of this getting accepted.  I'm pretty sure most modern network
> adapters have management CPU cores perfectly capable of running Linux.
> I know NFP does, here is the out-of-tree code equivalent to this patch:

LiquidIO is committed to ethtool and we are not trying to force users to
use this communication channel in place of ethtool. This communication
channel is for our field debug and informattion purposes and not for end
users. If most modern network adapters have management cores that can
run Linux, we could probably also think of finding a standard way to
talk to that Linux.

> 
> https://github.com/Netronome/nfp-drv-kmods/blob/master/src/nfpcore/nfp_net_vnic.c
> 
> I'm not looking forward to a world where I have to ssh into my NIC and
> run vendor commands to configure things.

We are not asking users to ssh into card and run vendor commands. Users
of LiquidIO card will continue to use ethtool for configuration. This is
for our field debugging where we would like to login to the linux and be
able to know the status of different hardware blocks in the card.

^ permalink raw reply

* Re: [PATCH net] ipv6: set fc_protocol with 0 when rtm_protocol is RTPROT_REDIRECT
From: Xin Long @ 2017-08-01  1:40 UTC (permalink / raw)
  To: David Ahern; +Cc: network dev, davem, Mantas Mikulėnas
In-Reply-To: <11af493f-1128-cae6-d1a3-0d3d962da269@gmail.com>

On Tue, Aug 1, 2017 at 12:12 PM, David Ahern <dsahern@gmail.com> wrote:
> On 7/30/17 9:31 PM, Xin Long wrote:
>>> Did you look at removing this hunk from rt6_fill_node:
>>>
>>>         if (rt->rt6i_flags & RTF_DYNAMIC)
>>>                 rtm->rtm_protocol = RTPROT_REDIRECT;
>>>         else if (rt->rt6i_flags & RTF_ADDRCONF) {
>>>                 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
>>>                         rtm->rtm_protocol = RTPROT_RA;
>>>                 else
>>>                         rtm->rtm_protocol = RTPROT_KERNEL;
>>>         }
>> The issue seems to affect "ip -6 route flush all" as well, not only cache
>> since 'else if {}' also  causes rtm proto being different from rt6 proto.
>>
>>>
>>> And have rtm_protocol set properly on the route when it is installed?
>> The codes not keeping rtm proto consistent with rt6 proto day 1,
>> any idea on why it didn't use rt6 proto in kernel properly?
>
> no, AFAIK it was just an oversight when the original code was written. I
> do not know of any reason that would prevent properly setting the
> rt6i_protocol in the route when it is allocated.
That's what I was worried about, it might break something,
but double checked, should be fine.

>
> Something like this (not compiled, much less tested):
To respect the old code more, setting RTPROT_RA only when
it's with the flag (ADDRCONF | DEFAULT | ROUTEINFO),
shouldn't it be:

[...]
@@ -2464,6 +2465,7 @@ static struct rt6_info
*rt6_add_route_info(struct net *net,
                .fc_nlinfo.portid = 0,
                .fc_nlinfo.nlh = NULL,
                .fc_nlinfo.nl_net = net,
+               .fc_protocol = RTPROT_KERNEL,
        };

        cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
@@ -2471,8 +2473,10 @@ static struct rt6_info
*rt6_add_route_info(struct net *net,
        cfg.fc_gateway = *gwaddr;

        /* We should treat it as a default route if prefix length is 0. */
-       if (!prefixlen)
+       if (!prefixlen) {
+               cfg.fc_protocol = RTPROT_RA;
                cfg.fc_flags |= RTF_DEFAULT;
+       }

        ip6_route_add(&cfg, NULL);

@@ -2516,6 +2520,7 @@ struct rt6_info *rt6_add_dflt_router(const
struct in6_addr *gwaddr,
                .fc_nlinfo.portid = 0,
                .fc_nlinfo.nlh = NULL,
                .fc_nlinfo.nl_net = dev_net(dev),
+               .fc_protocol = RTPROT_KERNEL,
        };
[...]

or you changed it intentionally ?

I will do some testing before posting v2.
thanks for your suggestion. :-)

>
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 4d30c96a819d..9a928839d247 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -2347,6 +2347,7 @@ static void rt6_do_redirect(struct dst_entry *dst,
> struct sock *sk, struct sk_bu
>         if (!nrt)
>                 goto out;
>
> +       nrt->rt6i_protocol = RTPROT_REDIRECT;
>         nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
>         if (on_link)
>                 nrt->rt6i_flags &= ~RTF_GATEWAY;
> @@ -2461,6 +2462,7 @@ static struct rt6_info *rt6_add_route_info(struct
> net *net,
>                 .fc_dst_len     = prefixlen,
>                 .fc_flags       = RTF_GATEWAY | RTF_ADDRCONF |
> RTF_ROUTEINFO |
>                                   RTF_UP | RTF_PREF(pref),
> +               .fc_protocol    = RTPROT_RA,
>                 .fc_nlinfo.portid = 0,
>                 .fc_nlinfo.nlh = NULL,
>                 .fc_nlinfo.nl_net = net,
> @@ -2513,6 +2515,7 @@ struct rt6_info *rt6_add_dflt_router(const struct
> in6_addr *gwaddr,
>                 .fc_ifindex     = dev->ifindex,
>                 .fc_flags       = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
>                                   RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
> +               .fc_protocol    = RTPROT_RA,
>                 .fc_nlinfo.portid = 0,
>                 .fc_nlinfo.nlh = NULL,
>                 .fc_nlinfo.nl_net = dev_net(dev),
> @@ -3424,14 +3427,6 @@ static int rt6_fill_node(struct net *net,
>         rtm->rtm_flags = 0;
>         rtm->rtm_scope = RT_SCOPE_UNIVERSE;
>         rtm->rtm_protocol = rt->rt6i_protocol;
> -       if (rt->rt6i_flags & RTF_DYNAMIC)
> -               rtm->rtm_protocol = RTPROT_REDIRECT;
> -       else if (rt->rt6i_flags & RTF_ADDRCONF) {
> -               if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO))
> -                       rtm->rtm_protocol = RTPROT_RA;
> -               else
> -                       rtm->rtm_protocol = RTPROT_KERNEL;
> -       }
>
>         if (rt->rt6i_flags & RTF_CACHE)
>                 rtm->rtm_flags |= RTM_F_CLONED;

^ permalink raw reply

* [PATCH v6 net-next] net: systemport: Support 64bit statistics
From: Jianming.qiao @ 2017-08-01  1:18 UTC (permalink / raw)
  To: f.fainelli, davem, eric.dumazet, netdev

When using Broadcom Systemport device in 32bit Platform, ifconfig can
only report up to 4G tx,rx status, which will be wrapped to 0 when the
number of incoming or outgoing packets exceeds 4G, only taking
around 2 hours in busy network environment (such as streaming).
Therefore, it makes hard for network diagnostic tool to get reliable
statistical result, so the patch is used to add 64bit support for
Broadcom Systemport device in 32bit Platform.

Signed-off-by: Jianming.qiao <kiki-good@hotmail.com>
---
 drivers/net/ethernet/broadcom/bcmsysport.c | 68 ++++++++++++++++++++----------
 drivers/net/ethernet/broadcom/bcmsysport.h |  9 +++-
 2 files changed, 52 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 5333601..bb3cc7a 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -662,6 +662,7 @@ static int bcm_sysport_alloc_rx_bufs(struct bcm_sysport_priv *priv)
 static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
 					unsigned int budget)
 {
+	struct bcm_sysport_stats *stats64 = &priv->stats64;
 	struct net_device *ndev = priv->netdev;
 	unsigned int processed = 0, to_process;
 	struct bcm_sysport_cb *cb;
@@ -765,6 +766,10 @@ static unsigned int bcm_sysport_desc_rx(struct bcm_sysport_priv *priv,
 		skb->protocol = eth_type_trans(skb, ndev);
 		ndev->stats.rx_packets++;
 		ndev->stats.rx_bytes += len;
+		u64_stats_update_begin(&stats64->syncp);
+		stats64->rx_packets++;
+		stats64->rx_bytes += len;
+		u64_stats_update_end(&stats64->syncp);
 
 		napi_gro_receive(&priv->napi, skb);
 next:
@@ -787,17 +792,15 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
 	struct device *kdev = &priv->pdev->dev;
 
 	if (cb->skb) {
-		ring->bytes += cb->skb->len;
 		*bytes_compl += cb->skb->len;
 		dma_unmap_single(kdev, dma_unmap_addr(cb, dma_addr),
 				 dma_unmap_len(cb, dma_len),
 				 DMA_TO_DEVICE);
-		ring->packets++;
 		(*pkts_compl)++;
 		bcm_sysport_free_cb(cb);
 	/* SKB fragment */
 	} else if (dma_unmap_addr(cb, dma_addr)) {
-		ring->bytes += dma_unmap_len(cb, dma_len);
+		*bytes_compl += dma_unmap_len(cb, dma_len);
 		dma_unmap_page(kdev, dma_unmap_addr(cb, dma_addr),
 			       dma_unmap_len(cb, dma_len), DMA_TO_DEVICE);
 		dma_unmap_addr_set(cb, dma_addr, 0);
@@ -808,9 +811,10 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
 static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
 					     struct bcm_sysport_tx_ring *ring)
 {
-	struct net_device *ndev = priv->netdev;
 	unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
+	struct bcm_sysport_stats *stats64 = &priv->stats64;
 	unsigned int pkts_compl = 0, bytes_compl = 0;
+	struct net_device *ndev = priv->netdev;
 	struct bcm_sysport_cb *cb;
 	u32 hw_ind;
 
@@ -849,6 +853,11 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
 		last_c_index &= (num_tx_cbs - 1);
 	}
 
+	u64_stats_update_begin(&stats64->syncp);
+	ring->packets += pkts_compl;
+	ring->bytes += bytes_compl;
+	u64_stats_update_end(&stats64->syncp);
+
 	ring->c_index = c_index;
 
 	netif_dbg(priv, tx_done, ndev,
@@ -1671,24 +1680,6 @@ static int bcm_sysport_change_mac(struct net_device *dev, void *p)
 	return 0;
 }
 
-static struct net_device_stats *bcm_sysport_get_nstats(struct net_device *dev)
-{
-	struct bcm_sysport_priv *priv = netdev_priv(dev);
-	unsigned long tx_bytes = 0, tx_packets = 0;
-	struct bcm_sysport_tx_ring *ring;
-	unsigned int q;
-
-	for (q = 0; q < dev->num_tx_queues; q++) {
-		ring = &priv->tx_rings[q];
-		tx_bytes += ring->bytes;
-		tx_packets += ring->packets;
-	}
-
-	dev->stats.tx_bytes = tx_bytes;
-	dev->stats.tx_packets = tx_packets;
-	return &dev->stats;
-}
-
 static void bcm_sysport_netif_start(struct net_device *dev)
 {
 	struct bcm_sysport_priv *priv = netdev_priv(dev);
@@ -1923,6 +1914,37 @@ static int bcm_sysport_stop(struct net_device *dev)
 	return 0;
 }
 
+static void bcm_sysport_get_stats64(struct net_device *dev,
+				    struct rtnl_link_stats64 *stats)
+{
+	struct bcm_sysport_priv *priv = netdev_priv(dev);
+	struct bcm_sysport_stats *stats64 = &priv->stats64;
+	struct bcm_sysport_tx_ring *ring;
+	u64 tx_packets = 0, tx_bytes = 0;
+	unsigned int start;
+	unsigned int q;
+
+	netdev_stats_to_stats64(stats, &dev->stats);
+
+	for (q = 0; q < dev->num_tx_queues; q++) {
+		ring = &priv->tx_rings[q];
+		do {
+			start = u64_stats_fetch_begin_irq(&stats64->syncp);
+			tx_bytes = ring->bytes;
+			tx_packets = ring->packets;
+		} while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
+
+		stats->tx_bytes += tx_bytes;
+		stats->tx_packets += tx_packets;
+	}
+
+	do {
+		start = u64_stats_fetch_begin_irq(&stats64->syncp);
+		stats->rx_packets = stats64->rx_packets;
+		stats->rx_bytes = stats64->rx_bytes;
+	} while (u64_stats_fetch_retry_irq(&stats64->syncp, start));
+}
+
 static const struct ethtool_ops bcm_sysport_ethtool_ops = {
 	.get_drvinfo		= bcm_sysport_get_drvinfo,
 	.get_msglevel		= bcm_sysport_get_msglvl,
@@ -1950,7 +1972,7 @@ static int bcm_sysport_stop(struct net_device *dev)
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= bcm_sysport_poll_controller,
 #endif
-	.ndo_get_stats		= bcm_sysport_get_nstats,
+	.ndo_get_stats64	= bcm_sysport_get_stats64,
 };
 
 #define REV_FMT	"v%2x.%02x"
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 77a51c1..c03a176 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -657,6 +657,9 @@ struct bcm_sysport_stats {
 	enum bcm_sysport_stat_type type;
 	/* reg offset from UMAC base for misc counters */
 	u16 reg_offset;
+	u64     rx_packets;
+	u64     rx_bytes;
+	struct u64_stats_sync   syncp;
 };
 
 /* Software house keeping helper structure */
@@ -693,8 +696,8 @@ struct bcm_sysport_tx_ring {
 	struct bcm_sysport_cb *cbs;	/* Transmit control blocks */
 	struct dma_desc	*desc_cpu;	/* CPU view of the descriptor */
 	struct bcm_sysport_priv *priv;	/* private context backpointer */
-	unsigned long	packets;	/* packets statistics */
-	unsigned long	bytes;		/* bytes statistics */
+	u64	packets;		/* packets statistics */
+	u64	bytes;			/* bytes statistics */
 };
 
 /* Driver private structure */
@@ -743,5 +746,7 @@ struct bcm_sysport_priv {
 
 	/* Ethtool */
 	u32			msg_enable;
+	/* 64bit stats on 32bit/64bit Machine */
+	struct bcm_sysport_stats stats64;
 };
 #endif /* __BCM_SYSPORT_H */
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH net] Revert "net: bcmgenet: Remove init parameter from bcmgenet_mii_config"
From: David Miller @ 2017-08-01  1:03 UTC (permalink / raw)
  To: f.fainelli; +Cc: netdev, opendmb, jaedon.shin
In-Reply-To: <20170731180532.19884-1-f.fainelli@gmail.com>

From: Florian Fainelli <f.fainelli@gmail.com>
Date: Mon, 31 Jul 2017 11:05:32 -0700

> This reverts commit 28b45910ccda ("net: bcmgenet: Remove init parameter
> from bcmgenet_mii_config") because in the process of moving from
> dev_info() to dev_info_once() we essentially lost the helpful printed
> messages once the second instance of the driver is loaded.
> dev_info_once() does not actually print the message once per device
> instance, but once period.
> 
> Fixes: 28b45910ccda ("net: bcmgenet: Remove init parameter from bcmgenet_mii_config")
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>

Applied, thanks Florian.

^ permalink raw reply

* Re: [PATCH net-next] ipv6: Avoid going through ->sk_net to access the netns
From: David Miller @ 2017-08-01  1:02 UTC (permalink / raw)
  To: jkbs; +Cc: netdev
In-Reply-To: <20170731080941.4920-1-jkbs@redhat.com>

From: Jakub Sitnicki <jkbs@redhat.com>
Date: Mon, 31 Jul 2017 10:09:41 +0200

> There is no need to go through sk->sk_net to access the net namespace
> and its sysctl variables because we allocate the sock and initialize
> sk_net just a few lines earlier in the same routine.
> 
> Signed-off-by: Jakub Sitnicki <jkbs@redhat.com>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH net-next 0/7] More Marvell PHY refactoring and cleanup
From: David Miller @ 2017-08-01  1:01 UTC (permalink / raw)
  To: andrew; +Cc: netdev, f.fainelli
In-Reply-To: <1501447310-24101-1-git-send-email-andrew@lunn.ch>

From: Andrew Lunn <andrew@lunn.ch>
Date: Sun, 30 Jul 2017 22:41:43 +0200

> Consolidate more duplicated code into helpers, make use of core
> helpers, move code into a helper for later adding functionality to add
> marvell PHYs, etc.

Series applied.

^ permalink raw reply

* Re: [PATCH V2 net-next 0/2] liquidio: Add support for managing liquidio adapter
From: David Miller @ 2017-08-01  0:59 UTC (permalink / raw)
  To: simon.horman
  Cc: felix.manlunas, netdev, raghu.vatsavayi, derek.chickles,
	satananda.burla, veerasenareddy.burru, jakub.kicinski
In-Reply-To: <20170730202103.GA8969@vergenet.net>

From: Simon Horman <simon.horman@netronome.com>
Date: Sun, 30 Jul 2017 22:21:04 +0200

> On Fri, Jul 28, 2017 at 11:17:07PM -0700, Felix Manlunas wrote:
>> From: Veerasenareddy Burru <veerasenareddy.burru@cavium.com>
>> 
>> The LiquidIO adapter has processor cores that can run Linux. This patch
>> set adds support to create a virtual Ethernet interface on host to
>> communicate with applications running on Linux in the LiquidIO adapter.
>> The virtual Ethernet interface also provides login access to Linux on
>> LiquidIO through ssh for management and debugging.
> 
> As per the somewhat more detailed feedback provided by my colleague Jakub
> Kicinski to v1 of this patchset[1] I am concerned that this patchset breaks down
> the long standing practice of not granting direct access to firmware from
> userspace.
> 
> [1] https://www.spinics.net/lists/netdev/msg444929.html

Agreed, I've seen no attempt to address this important feedback, which
I agree with.

^ permalink raw reply

* Re: [PATCH] mv643xx_eth: fix of_irq_to_resource() error check
From: David Miller @ 2017-08-01  0:57 UTC (permalink / raw)
  To: sergei.shtylyov; +Cc: sebastian.hesselbarth, netdev, thomas.petazzoni
In-Reply-To: <20170729191901.922633706@cogentembedded.com>

From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Date: Sat, 29 Jul 2017 22:18:41 +0300

> of_irq_to_resource() has recently been  fixed to return negative error #'s
> along with 0 in case of failure,  however the Marvell MV643xx Ethernet
> driver still only regards 0  as invalid IRQ -- fix it up.
> 
> Fixes: 7a4228bbff76 ("of: irq: use of_irq_get() in of_irq_to_resource()")
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>

Applied.

^ permalink raw reply

* Re: [PATCH] net-next: stmmac: dwmac-sun8i: fix of_table.cocci warnings
From: David Miller @ 2017-08-01  0:56 UTC (permalink / raw)
  To: julia.lawall-L2FTfq7BK8M
  Cc: clabbe.montjoie-Re5JQEeQqe8AvxtiuMwx3w,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, wens-jdAy2FN1RRM,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, peppe.cavallaro-qxv4g6HH51o,
	alexandre.torgue-qxv4g6HH51o, icenowy-h8G6r0blFSE,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, kbuild-all-JC7UmRfGjtg
In-Reply-To: <alpine.DEB.2.20.1707291752210.2069@hadrien>

From: Julia Lawall <julia.lawall-L2FTfq7BK8M@public.gmane.org>
Date: Sat, 29 Jul 2017 17:54:10 +0200 (CEST)

> Make sure (of/i2c/platform)_device_id tables are NULL terminated
> 
> Generated by: scripts/coccinelle/misc/of_table.cocci
> 
> Fixes: d5dbe1976d52 ("net-next: stmmac: dwmac-sun8i: choose internal PHY via compatible")
> CC: Corentin Labbe <clabbe.montjoie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Fengguang Wu <fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>

This change seems to be no longer relevant.
--
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


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