Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 2/3] netpoll: add IPv6 support
From: Cong Wang @ 2013-01-01  8:01 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Cong Wang
In-Reply-To: <1357027288-28675-1-git-send-email-amwang@redhat.com>

From: Cong Wang <amwang@redhat.com>

Currently, netpoll only support IPv4. This patch adds IPv6
support to netpoll, so that we can run netconsole over IPv6 network.

Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
 drivers/net/netconsole.c |   44 +++++++-
 include/net/udp.h        |    2 +
 net/core/netpoll.c       |  246 ++++++++++++++++++++++++++++++++++++++++++++--
 net/ipv6/udp.c           |    3 +-
 4 files changed, 277 insertions(+), 18 deletions(-)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 998fa02..2fd281a 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,13 +269,17 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-	if (!nt->np.ipv6)
+	if (nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+	else
 		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-	if (!nt->np.ipv6)
+	if (nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+	else
 		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
@@ -412,8 +416,22 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
 		return -EINVAL;
 	}
 
-	if (!strnchr(buf, count, ':'))
-		nt->np.local_ip.ip = in_aton(buf);
+	if (strnchr(buf, count, ':')) {
+		const char *end;
+		if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+			if (*end && *end != '\n') {
+				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+				return -EINVAL;
+			}
+			nt->np.ipv6 = 1;
+		} else
+			return -EINVAL;
+	} else {
+		if (!nt->np.ipv6)
+			nt->np.local_ip.ip = in_aton(buf);
+		else
+			return -EINVAL;
+	}
 
 	return strnlen(buf, count);
 }
@@ -429,8 +447,22 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
 		return -EINVAL;
 	}
 
-	if (!strnchr(buf, count, ':'))
-		nt->np.remote_ip.ip = in_aton(buf);
+	if (strnchr(buf, count, ':')) {
+		const char *end;
+		if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+			if (*end && *end != '\n') {
+				printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+				return -EINVAL;
+			}
+			nt->np.ipv6 = 1;
+		} else
+			return -EINVAL;
+	} else {
+		if (!nt->np.ipv6)
+			nt->np.remote_ip.ip = in_aton(buf);
+		else
+			return -EINVAL;
+	}
 
 	return strnlen(buf, count);
 }
diff --git a/include/net/udp.h b/include/net/udp.h
index 065f379..c3ddb4a 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -156,6 +156,8 @@ static inline __wsum udp_csum(struct sk_buff *skb)
 	return csum;
 }
 
+extern int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto);
+
 /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
 static inline void udp_lib_hash(struct sock *sk)
 {
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 46e8d1c..a2cafa3 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -29,6 +29,8 @@
 #include <linux/if_vlan.h>
 #include <net/tcp.h>
 #include <net/udp.h>
+#include <net/addrconf.h>
+#include <net/ndisc.h>
 #include <asm/unaligned.h>
 #include <trace/events/napi.h>
 
@@ -381,9 +383,12 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 	struct iphdr *iph;
 	struct ethhdr *eth;
 	static atomic_t ip_ident;
+	struct ipv6hdr *ip6h;
 
 	udp_len = len + sizeof(*udph);
-	if (!np->ipv6)
+	if (np->ipv6)
+		ip_len = udp_len + sizeof(*ip6h);
+	else
 		ip_len = udp_len + sizeof(*iph);
 
 	total_len = ip_len + LL_RESERVED_SPACE(np->dev);
@@ -403,7 +408,35 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 	udph->dest = htons(np->remote_port);
 	udph->len = htons(udp_len);
 
-	if (!np->ipv6) {
+	if (np->ipv6) {
+		udph->check = 0;
+		udph->check = csum_ipv6_magic(&np->local_ip.in6,
+					      &np->remote_ip.in6,
+					      udp_len, IPPROTO_UDP,
+					      csum_partial(udph, udp_len, 0));
+		if (udph->check == 0)
+			udph->check = CSUM_MANGLED_0;
+
+		skb_push(skb, sizeof(*ip6h));
+		skb_reset_network_header(skb);
+		ip6h = ipv6_hdr(skb);
+
+		/* ip6h->version = 6; ip6h->priority = 0; */
+		put_unaligned(0x60, (unsigned char *)ip6h);
+		ip6h->flow_lbl[0] = 0;
+		ip6h->flow_lbl[1] = 0;
+		ip6h->flow_lbl[2] = 0;
+
+		ip6h->payload_len = htons(sizeof(struct udphdr) + len);
+		ip6h->nexthdr = IPPROTO_UDP;
+		ip6h->hop_limit = 32;
+		ip6h->saddr = np->local_ip.in6;
+		ip6h->daddr = np->remote_ip.in6;
+
+		eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+		skb_reset_mac_header(skb);
+		skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
+	} else {
 		udph->check = 0;
 		udph->check = csum_tcpudp_magic(np->local_ip.ip,
 						np->remote_ip.ip,
@@ -445,9 +478,7 @@ EXPORT_SYMBOL(netpoll_send_udp);
 
 static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
-	struct arphdr *arp;
-	unsigned char *arp_ptr;
-	int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
+	int size, type = ARPOP_REPLY;
 	__be32 sip, tip;
 	unsigned char *sha;
 	struct sk_buff *send_skb;
@@ -474,6 +505,8 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
 
 	proto = ntohs(eth_hdr(skb)->h_proto);
 	if (proto == ETH_P_IP) {
+		struct arphdr *arp;
+		unsigned char *arp_ptr;
 		/* No arp on this interface */
 		if (skb->dev->flags & IFF_NOARP)
 			return;
@@ -525,7 +558,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
 			send_skb->protocol = htons(ETH_P_ARP);
 
 			/* Fill the device header for the ARP frame */
-			if (dev_hard_header(send_skb, skb->dev, ptype,
+			if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP,
 					    sha, np->dev->dev_addr,
 					    send_skb->len) < 0) {
 				kfree_skb(send_skb);
@@ -562,14 +595,140 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
 			break;
 		}
 		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+	} else if( proto == ETH_P_IPV6) {
+		struct nd_msg *msg;
+		struct ndisc_options ndopts;
+		u8 *lladdr = NULL;
+		struct ipv6hdr *hdr;
+		struct icmp6hdr *icmp6h;
+		const struct in6_addr *saddr;
+		const struct in6_addr *daddr;
+		struct inet6_dev *in6_dev = NULL;
+		u32 ndoptlen;
+		struct in6_addr *target;
+
+		in6_dev = in6_dev_get(skb->dev);
+		if (!in6_dev || !in6_dev->cnf.accept_ra)
+			return;
+
+		if (!pskb_may_pull(skb, skb->len))
+			return;
+
+		msg = (struct nd_msg *)skb_transport_header(skb);
+
+		__skb_push(skb, skb->data - skb_transport_header(skb));
+
+		if (ipv6_hdr(skb)->hop_limit != 255)
+			return;
+		if (msg->icmph.icmp6_code != 0)
+			return;
+		if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+			return;
+
+		saddr = &ipv6_hdr(skb)->saddr;
+		daddr = &ipv6_hdr(skb)->daddr;
+
+		ndoptlen = skb->tail - (skb->transport_header + offsetof(struct nd_msg, opt));
+		if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
+			return;
+
+		if (ndopts.nd_opts_src_lladdr) {
+			lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, skb->dev);
+			if (!lladdr)
+				return;
+		}
+
+		size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+			if (memcmp(daddr, &np->local_ip, sizeof(*daddr)))
+				continue;
+
+			hlen = LL_RESERVED_SPACE(np->dev);
+			tlen = np->dev->needed_tailroom;
+			send_skb = find_skb(np, size + hlen + tlen, hlen);
+			if (!send_skb)
+				continue;
+
+			send_skb->protocol = htons(ETH_P_IPV6);
+			send_skb->dev = skb->dev;
+
+			skb_reset_network_header(send_skb);
+			skb_put(send_skb, sizeof(struct ipv6hdr));
+			hdr = ipv6_hdr(send_skb);
+
+			*(__be32*)hdr = htonl(0x60000000);
+
+			hdr->payload_len = htons(size);
+			hdr->nexthdr = IPPROTO_ICMPV6;
+			hdr->hop_limit = 255;
+			hdr->saddr = *saddr;
+			hdr->daddr = *daddr;
+
+			send_skb->transport_header = send_skb->tail;
+			skb_put(send_skb, size);
+
+			icmp6h = (struct icmp6hdr *)skb_transport_header(skb);
+			icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+			icmp6h->icmp6_router = 0;
+			icmp6h->icmp6_solicited = 1;
+			target = (struct in6_addr *)skb_transport_header(send_skb) + sizeof(struct icmp6hdr);
+			*target = msg->target;
+			icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size,
+							      IPPROTO_ICMPV6,
+							      csum_partial(icmp6h,
+									   size, 0));
+
+			if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6,
+					    lladdr, np->dev->dev_addr,
+					    send_skb->len) < 0) {
+				kfree_skb(send_skb);
+				continue;
+			}
+
+			netpoll_send_skb(np, send_skb);
+
+			/* If there are several rx_hooks for the same address,
+			   we're fine by sending a single reply */
+			break;
+		}
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 	}
 }
 
+static bool pkt_is_ns(struct sk_buff *skb)
+{
+	struct nd_msg *msg;
+	struct ipv6hdr *hdr;
+
+	if (skb->protocol != htons(ETH_P_ARP))
+		return false;
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
+		return false;
+
+	msg = (struct nd_msg *)skb_transport_header(skb);
+	__skb_push(skb, skb->data - skb_transport_header(skb));
+	hdr = ipv6_hdr(skb);
+
+	if (hdr->nexthdr != IPPROTO_ICMPV6)
+		return false;
+	if (hdr->hop_limit != 255)
+		return false;
+	if (msg->icmph.icmp6_code != 0)
+		return false;
+	if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+		return false;
+
+	return true;
+}
+
 int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
 	int proto, len, ulen;
 	int hits = 0;
 	const struct iphdr *iph;
+	const struct ipv6hdr *ip6h;
 	struct udphdr *uh;
 	struct netpoll *np, *tmp;
 
@@ -580,8 +739,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 		goto out;
 
 	/* check if netpoll clients need ARP */
-	if (skb->protocol == htons(ETH_P_ARP) &&
-	    atomic_read(&trapped)) {
+	if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) {
+		skb_queue_tail(&npinfo->neigh_tx, skb);
+		return 1;
+	} else if (pkt_is_ns(skb) && atomic_read(&trapped)) {
 		skb_queue_tail(&npinfo->neigh_tx, skb);
 		return 1;
 	}
@@ -648,6 +809,41 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 				       ulen - sizeof(struct udphdr));
 			hits++;
 		}
+	} else {
+		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+			goto out;
+		ip6h = (struct ipv6hdr *)skb->data;
+		if (ip6h->version != 6)
+			goto out;
+		len = ntohs(ip6h->payload_len);
+		if (!len)
+			goto out;
+		if (len + sizeof(struct ipv6hdr) > skb->len)
+			goto out;
+		if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
+			goto out;
+		ip6h = ipv6_hdr(skb);
+		if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+			goto out;
+		uh = udp_hdr(skb);
+		ulen = ntohs(uh->len);
+		if (ulen != skb->len)
+			goto out;
+		if (udp6_csum_init(skb, uh, IPPROTO_UDP))
+			goto out;
+		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+			if (memcmp(&np->local_ip.in6, &ip6h->daddr, sizeof(struct in6_addr)) != 0)
+				continue;
+			if (memcmp(&np->remote_ip.in6, &ip6h->saddr, sizeof(struct in6_addr)) != 0)
+				continue;
+			if (np->local_port && np->local_port != ntohs(uh->dest))
+				continue;
+
+			np->rx_hook(np, ntohs(uh->source),
+				       (char *)(uh+1),
+				       ulen - sizeof(struct udphdr));
+			hits++;
+		}
 	}
 
 	if (!hits)
@@ -668,11 +864,15 @@ out:
 void netpoll_print_options(struct netpoll *np)
 {
 	np_info(np, "local port %d\n", np->local_port);
-	if (!np->ipv6)
+	if (np->ipv6)
+		np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
+	else
 		np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
 	np_info(np, "interface '%s'\n", np->dev_name);
 	np_info(np, "remote port %d\n", np->remote_port);
-	if (!np->ipv6)
+	if (np->ipv6)
+		np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
+	else
 		np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
 	np_info(np, "remote ethernet address %pM\n", np->remote_mac);
 }
@@ -912,6 +1112,32 @@ int netpoll_setup(struct netpoll *np)
 			np->local_ip.ip = in_dev->ifa_list->ifa_local;
 			rcu_read_unlock();
 			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+		} else {
+			struct inet6_dev *idev;
+
+			err = -EDESTADDRREQ;
+			rcu_read_lock();
+			idev = __in6_dev_get(ndev);
+			if (idev) {
+				struct inet6_ifaddr *ifp;
+
+				read_lock_bh(&idev->lock);
+				list_for_each_entry(ifp, &idev->addr_list, if_list) {
+					if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
+						continue;
+					np->local_ip.in6 = ifp->addr;
+					err = 0;
+					break;
+				}
+				read_unlock_bh(&idev->lock);
+			}
+			rcu_read_unlock();
+			if (err) {
+				np_err(np, "no IPv6 address for %s, aborting\n",
+				       np->dev_name);
+				goto put;
+			} else
+				np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
 		}
 	}
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index dfaa29b..285754c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -752,8 +752,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 	return 0;
 }
 
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
-				 int proto)
+int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
 {
 	int err;
 
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH net-next 3/3] netconsole: add IPv6 example in doc
From: Cong Wang @ 2013-01-01  8:01 UTC (permalink / raw)
  To: netdev; +Cc: Cong Wang
In-Reply-To: <1357027288-28675-1-git-send-email-amwang@redhat.com>

From: Cong Wang <amwang@redhat.com>

Update the netconsole document as well.

Signed-off-by: Cong Wang <amwang@redhat.com>
---
 Documentation/networking/netconsole.txt |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index 2e9e0ae2..a5d574a 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -1,9 +1,10 @@
 
 started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
 2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
 
 Please send bug reports to Matt Mackall <mpm@selenic.com>
-and Satyam Sharma <satyam.sharma@gmail.com>
+Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
 
 Introduction:
 =============
@@ -41,6 +42,10 @@ Examples:
 
  insmod netconsole netconsole=@/,@10.0.0.2/
 
+  or using IPv6
+
+ insmod netconsole netconsole=@/,@fd00:1:2:3::1/
+
 It also supports logging to multiple remote agents by specifying
 parameters for the multiple agents separated by semicolons and the
 complete string enclosed in "quotes", thusly:
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH net-next 1/3] netpoll: prepare for ipv6
From: Cong Wang @ 2013-01-01  8:01 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Cong Wang

From: Cong Wang <amwang@redhat.com>

This patch adjusts some struct and functions, to prepare
for supporting IPv6.

Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
 drivers/net/netconsole.c |   12 +-
 include/linux/netpoll.h  |   13 ++-
 net/core/netpoll.c       |  398 +++++++++++++++++++++++++---------------------
 3 files changed, 239 insertions(+), 184 deletions(-)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 6989ebe..998fa02 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,12 +269,14 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+	if (!nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+	if (!nt->np.ipv6)
+		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +412,8 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
 		return -EINVAL;
 	}
 
-	nt->np.local_ip = in_aton(buf);
+	if (!strnchr(buf, count, ':'))
+		nt->np.local_ip.ip = in_aton(buf);
 
 	return strnlen(buf, count);
 }
@@ -426,7 +429,8 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
 		return -EINVAL;
 	}
 
-	nt->np.remote_ip = in_aton(buf);
+	if (!strnchr(buf, count, ':'))
+		nt->np.remote_ip.ip = in_aton(buf);
 
 	return strnlen(buf, count);
 }
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 66d5379..24da730 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -12,13 +12,22 @@
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 
+union inet_addr {
+	__u32		all[4];
+	__be32		ip;
+	__be32		ip6[4];
+	struct in_addr	in;
+	struct in6_addr	in6;
+};
+
 struct netpoll {
 	struct net_device *dev;
 	char dev_name[IFNAMSIZ];
 	const char *name;
 	void (*rx_hook)(struct netpoll *, int, char *, int);
 
-	__be32 local_ip, remote_ip;
+	int ipv6;
+	union inet_addr local_ip, remote_ip;
 	u16 local_port, remote_port;
 	u8 remote_mac[ETH_ALEN];
 
@@ -33,7 +42,7 @@ struct netpoll_info {
 	spinlock_t rx_lock;
 	struct list_head rx_np; /* netpolls that registered an rx_hook */
 
-	struct sk_buff_head arp_tx; /* list of arp requests to reply to */
+	struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
 	struct sk_buff_head txq;
 
 	struct delayed_work tx_work;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 3151acf..46e8d1c 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -55,7 +55,7 @@ static atomic_t trapped;
 	 MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 
 static unsigned int carrier_timeout = 4;
 module_param(carrier_timeout, uint, 0644);
@@ -181,13 +181,13 @@ static void poll_napi(struct net_device *dev)
 	}
 }
 
-static void service_arp_queue(struct netpoll_info *npi)
+static void service_neigh_queue(struct netpoll_info *npi)
 {
 	if (npi) {
 		struct sk_buff *skb;
 
-		while ((skb = skb_dequeue(&npi->arp_tx)))
-			netpoll_arp_reply(skb, npi);
+		while ((skb = skb_dequeue(&npi->neigh_tx)))
+			netpoll_neigh_reply(skb, npi);
 	}
 }
 
@@ -213,14 +213,14 @@ static void netpoll_poll_dev(struct net_device *dev)
 			struct net_device *bond_dev = dev->master;
 			struct sk_buff *skb;
 			struct netpoll_info *bond_ni = rcu_dereference_bh(bond_dev->npinfo);
-			while ((skb = skb_dequeue(&ni->arp_tx))) {
+			while ((skb = skb_dequeue(&ni->neigh_tx))) {
 				skb->dev = bond_dev;
-				skb_queue_tail(&bond_ni->arp_tx, skb);
+				skb_queue_tail(&bond_ni->neigh_tx, skb);
 			}
 		}
 	}
 
-	service_arp_queue(ni);
+	service_neigh_queue(ni);
 
 	zap_completion_queue();
 }
@@ -383,7 +383,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 	static atomic_t ip_ident;
 
 	udp_len = len + sizeof(*udph);
-	ip_len = udp_len + sizeof(*iph);
+	if (!np->ipv6)
+		ip_len = udp_len + sizeof(*iph);
+
 	total_len = ip_len + LL_RESERVED_SPACE(np->dev);
 
 	skb = find_skb(np, total_len + np->dev->needed_tailroom,
@@ -400,34 +402,38 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 	udph->source = htons(np->local_port);
 	udph->dest = htons(np->remote_port);
 	udph->len = htons(udp_len);
-	udph->check = 0;
-	udph->check = csum_tcpudp_magic(np->local_ip,
-					np->remote_ip,
-					udp_len, IPPROTO_UDP,
-					csum_partial(udph, udp_len, 0));
-	if (udph->check == 0)
-		udph->check = CSUM_MANGLED_0;
-
-	skb_push(skb, sizeof(*iph));
-	skb_reset_network_header(skb);
-	iph = ip_hdr(skb);
-
-	/* iph->version = 4; iph->ihl = 5; */
-	put_unaligned(0x45, (unsigned char *)iph);
-	iph->tos      = 0;
-	put_unaligned(htons(ip_len), &(iph->tot_len));
-	iph->id       = htons(atomic_inc_return(&ip_ident));
-	iph->frag_off = 0;
-	iph->ttl      = 64;
-	iph->protocol = IPPROTO_UDP;
-	iph->check    = 0;
-	put_unaligned(np->local_ip, &(iph->saddr));
-	put_unaligned(np->remote_ip, &(iph->daddr));
-	iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-	eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-	skb_reset_mac_header(skb);
-	skb->protocol = eth->h_proto = htons(ETH_P_IP);
+
+	if (!np->ipv6) {
+		udph->check = 0;
+		udph->check = csum_tcpudp_magic(np->local_ip.ip,
+						np->remote_ip.ip,
+						udp_len, IPPROTO_UDP,
+						csum_partial(udph, udp_len, 0));
+		if (udph->check == 0)
+			udph->check = CSUM_MANGLED_0;
+
+		skb_push(skb, sizeof(*iph));
+		skb_reset_network_header(skb);
+		iph = ip_hdr(skb);
+
+		/* iph->version = 4; iph->ihl = 5; */
+		put_unaligned(0x45, (unsigned char *)iph);
+		iph->tos      = 0;
+		put_unaligned(htons(ip_len), &(iph->tot_len));
+		iph->id       = htons(atomic_inc_return(&ip_ident));
+		iph->frag_off = 0;
+		iph->ttl      = 64;
+		iph->protocol = IPPROTO_UDP;
+		iph->check    = 0;
+		put_unaligned(np->local_ip.ip, &(iph->saddr));
+		put_unaligned(np->remote_ip.ip, &(iph->daddr));
+		iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+		eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+		skb_reset_mac_header(skb);
+		skb->protocol = eth->h_proto = htons(ETH_P_IP);
+	}
+
 	memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
 	memcpy(eth->h_dest, np->remote_mac, ETH_ALEN);
 
@@ -437,7 +443,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
 	struct arphdr *arp;
 	unsigned char *arp_ptr;
@@ -448,7 +454,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 	struct netpoll *np, *tmp;
 	unsigned long flags;
 	int hlen, tlen;
-	int hits = 0;
+	int hits = 0, proto;
 
 	if (list_empty(&npinfo->rx_np))
 		return;
@@ -466,94 +472,97 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 	if (!hits)
 		return;
 
-	/* No arp on this interface */
-	if (skb->dev->flags & IFF_NOARP)
-		return;
-
-	if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
-		return;
+	proto = ntohs(eth_hdr(skb)->h_proto);
+	if (proto == ETH_P_IP) {
+		/* No arp on this interface */
+		if (skb->dev->flags & IFF_NOARP)
+			return;
 
-	skb_reset_network_header(skb);
-	skb_reset_transport_header(skb);
-	arp = arp_hdr(skb);
+		if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
+			return;
 
-	if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
-	     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
-	    arp->ar_pro != htons(ETH_P_IP) ||
-	    arp->ar_op != htons(ARPOP_REQUEST))
-		return;
+		skb_reset_network_header(skb);
+		skb_reset_transport_header(skb);
+		arp = arp_hdr(skb);
 
-	arp_ptr = (unsigned char *)(arp+1);
-	/* save the location of the src hw addr */
-	sha = arp_ptr;
-	arp_ptr += skb->dev->addr_len;
-	memcpy(&sip, arp_ptr, 4);
-	arp_ptr += 4;
-	/* If we actually cared about dst hw addr,
-	   it would get copied here */
-	arp_ptr += skb->dev->addr_len;
-	memcpy(&tip, arp_ptr, 4);
-
-	/* Should we ignore arp? */
-	if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
-		return;
+		if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+		     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+		    arp->ar_pro != htons(ETH_P_IP) ||
+		    arp->ar_op != htons(ARPOP_REQUEST))
+			return;
 
-	size = arp_hdr_len(skb->dev);
+		arp_ptr = (unsigned char *)(arp+1);
+		/* save the location of the src hw addr */
+		sha = arp_ptr;
+		arp_ptr += skb->dev->addr_len;
+		memcpy(&sip, arp_ptr, 4);
+		arp_ptr += 4;
+		/* If we actually cared about dst hw addr,
+		   it would get copied here */
+		arp_ptr += skb->dev->addr_len;
+		memcpy(&tip, arp_ptr, 4);
 
-	spin_lock_irqsave(&npinfo->rx_lock, flags);
-	list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-		if (tip != np->local_ip)
-			continue;
+		/* Should we ignore arp? */
+		if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
+			return;
 
-		hlen = LL_RESERVED_SPACE(np->dev);
-		tlen = np->dev->needed_tailroom;
-		send_skb = find_skb(np, size + hlen + tlen, hlen);
-		if (!send_skb)
-			continue;
+		size = arp_hdr_len(skb->dev);
 
-		skb_reset_network_header(send_skb);
-		arp = (struct arphdr *) skb_put(send_skb, size);
-		send_skb->dev = skb->dev;
-		send_skb->protocol = htons(ETH_P_ARP);
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+			if (tip != np->local_ip.ip)
+				continue;
+
+			hlen = LL_RESERVED_SPACE(np->dev);
+			tlen = np->dev->needed_tailroom;
+			send_skb = find_skb(np, size + hlen + tlen, hlen);
+			if (!send_skb)
+				continue;
+
+			skb_reset_network_header(send_skb);
+			arp = (struct arphdr *) skb_put(send_skb, size);
+			send_skb->dev = skb->dev;
+			send_skb->protocol = htons(ETH_P_ARP);
+
+			/* Fill the device header for the ARP frame */
+			if (dev_hard_header(send_skb, skb->dev, ptype,
+					    sha, np->dev->dev_addr,
+					    send_skb->len) < 0) {
+				kfree_skb(send_skb);
+				continue;
+			}
 
-		/* Fill the device header for the ARP frame */
-		if (dev_hard_header(send_skb, skb->dev, ptype,
-				    sha, np->dev->dev_addr,
-				    send_skb->len) < 0) {
-			kfree_skb(send_skb);
-			continue;
+			/*
+			 * Fill out the arp protocol part.
+			 *
+			 * we only support ethernet device type,
+			 * which (according to RFC 1390) should
+			 * always equal 1 (Ethernet).
+			 */
+
+			arp->ar_hrd = htons(np->dev->type);
+			arp->ar_pro = htons(ETH_P_IP);
+			arp->ar_hln = np->dev->addr_len;
+			arp->ar_pln = 4;
+			arp->ar_op = htons(type);
+
+			arp_ptr = (unsigned char *)(arp + 1);
+			memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+			arp_ptr += np->dev->addr_len;
+			memcpy(arp_ptr, &tip, 4);
+			arp_ptr += 4;
+			memcpy(arp_ptr, sha, np->dev->addr_len);
+			arp_ptr += np->dev->addr_len;
+			memcpy(arp_ptr, &sip, 4);
+
+			netpoll_send_skb(np, send_skb);
+
+			/* If there are several rx_hooks for the same address,
+			   we're fine by sending a single reply */
+			break;
 		}
-
-		/*
-		 * Fill out the arp protocol part.
-		 *
-		 * we only support ethernet device type,
-		 * which (according to RFC 1390) should
-		 * always equal 1 (Ethernet).
-		 */
-
-		arp->ar_hrd = htons(np->dev->type);
-		arp->ar_pro = htons(ETH_P_IP);
-		arp->ar_hln = np->dev->addr_len;
-		arp->ar_pln = 4;
-		arp->ar_op = htons(type);
-
-		arp_ptr = (unsigned char *)(arp + 1);
-		memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
-		arp_ptr += np->dev->addr_len;
-		memcpy(arp_ptr, &tip, 4);
-		arp_ptr += 4;
-		memcpy(arp_ptr, sha, np->dev->addr_len);
-		arp_ptr += np->dev->addr_len;
-		memcpy(arp_ptr, &sip, 4);
-
-		netpoll_send_skb(np, send_skb);
-
-		/* If there are several rx_hooks for the same address,
-		   we're fine by sending a single reply */
-		break;
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 	}
-	spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 }
 
 int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
@@ -573,7 +582,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 	/* check if netpoll clients need ARP */
 	if (skb->protocol == htons(ETH_P_ARP) &&
 	    atomic_read(&trapped)) {
-		skb_queue_tail(&npinfo->arp_tx, skb);
+		skb_queue_tail(&npinfo->neigh_tx, skb);
 		return 1;
 	}
 
@@ -584,60 +593,61 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 	}
 
 	proto = ntohs(eth_hdr(skb)->h_proto);
-	if (proto != ETH_P_IP)
+	if (proto != ETH_P_IP && proto != ETH_P_IPV6)
 		goto out;
 	if (skb->pkt_type == PACKET_OTHERHOST)
 		goto out;
 	if (skb_shared(skb))
 		goto out;
 
-	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-		goto out;
-	iph = (struct iphdr *)skb->data;
-	if (iph->ihl < 5 || iph->version != 4)
-		goto out;
-	if (!pskb_may_pull(skb, iph->ihl*4))
-		goto out;
-	iph = (struct iphdr *)skb->data;
-	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-		goto out;
-
-	len = ntohs(iph->tot_len);
-	if (skb->len < len || len < iph->ihl*4)
-		goto out;
-
-	/*
-	 * Our transport medium may have padded the buffer out.
-	 * Now We trim to the true length of the frame.
-	 */
-	if (pskb_trim_rcsum(skb, len))
-		goto out;
+	if (proto == ETH_P_IP) {
+		if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+			goto out;
+		iph = (struct iphdr *)skb->data;
+		if (iph->ihl < 5 || iph->version != 4)
+			goto out;
+		if (!pskb_may_pull(skb, iph->ihl*4))
+			goto out;
+		iph = (struct iphdr *)skb->data;
+		if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+			goto out;
 
-	iph = (struct iphdr *)skb->data;
-	if (iph->protocol != IPPROTO_UDP)
-		goto out;
+		len = ntohs(iph->tot_len);
+		if (skb->len < len || len < iph->ihl*4)
+			goto out;
 
-	len -= iph->ihl*4;
-	uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
-	ulen = ntohs(uh->len);
+		/*
+		 * Our transport medium may have padded the buffer out.
+		 * Now We trim to the true length of the frame.
+		 */
+		if (pskb_trim_rcsum(skb, len))
+			goto out;
 
-	if (ulen != len)
-		goto out;
-	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
-		goto out;
+		iph = (struct iphdr *)skb->data;
+		if (iph->protocol != IPPROTO_UDP)
+			goto out;
 
-	list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-		if (np->local_ip && np->local_ip != iph->daddr)
-			continue;
-		if (np->remote_ip && np->remote_ip != iph->saddr)
-			continue;
-		if (np->local_port && np->local_port != ntohs(uh->dest))
-			continue;
+		len -= iph->ihl*4;
+		uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
+		ulen = ntohs(uh->len);
 
-		np->rx_hook(np, ntohs(uh->source),
-			       (char *)(uh+1),
-			       ulen - sizeof(struct udphdr));
-		hits++;
+		if (ulen != len)
+			goto out;
+		if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
+			goto out;
+		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+			if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
+				continue;
+			if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
+				continue;
+			if (np->local_port && np->local_port != ntohs(uh->dest))
+				continue;
+
+			np->rx_hook(np, ntohs(uh->source),
+				       (char *)(uh+1),
+				       ulen - sizeof(struct udphdr));
+			hits++;
+		}
 	}
 
 	if (!hits)
@@ -658,17 +668,36 @@ out:
 void netpoll_print_options(struct netpoll *np)
 {
 	np_info(np, "local port %d\n", np->local_port);
-	np_info(np, "local IP %pI4\n", &np->local_ip);
+	if (!np->ipv6)
+		np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
 	np_info(np, "interface '%s'\n", np->dev_name);
 	np_info(np, "remote port %d\n", np->remote_port);
-	np_info(np, "remote IP %pI4\n", &np->remote_ip);
+	if (!np->ipv6)
+		np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
 	np_info(np, "remote ethernet address %pM\n", np->remote_mac);
 }
 EXPORT_SYMBOL(netpoll_print_options);
 
+static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
+{
+	const char *end;
+
+	if (!strchr(str, ':') &&
+	    in4_pton(str, -1, (void *)addr, -1, &end) > 0) {
+		if (!*end)
+			return 0;
+	}
+	if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
+		if (!*end)
+			return 1;
+	}
+	return -1;
+}
+
 int netpoll_parse_options(struct netpoll *np, char *opt)
 {
 	char *cur=opt, *delim;
+	int ipv6;
 
 	if (*cur != '@') {
 		if ((delim = strchr(cur, '@')) == NULL)
@@ -684,7 +713,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 		if ((delim = strchr(cur, '/')) == NULL)
 			goto parse_failed;
 		*delim = 0;
-		np->local_ip = in_aton(cur);
+		ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
+		if (ipv6 < 0)
+			goto parse_failed;
+		else
+			np->ipv6 = ipv6;
 		cur = delim;
 	}
 	cur++;
@@ -716,7 +749,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 	if ((delim = strchr(cur, '/')) == NULL)
 		goto parse_failed;
 	*delim = 0;
-	np->remote_ip = in_aton(cur);
+	ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
+	if (ipv6 < 0)
+		goto parse_failed;
+	else if (np->ipv6 != ipv6)
+		goto parse_failed;
+	else
+		np->ipv6 = ipv6;
 	cur = delim + 1;
 
 	if (*cur != 0) {
@@ -764,7 +803,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 		INIT_LIST_HEAD(&npinfo->rx_np);
 
 		spin_lock_init(&npinfo->rx_lock);
-		skb_queue_head_init(&npinfo->arp_tx);
+		skb_queue_head_init(&npinfo->neigh_tx);
 		skb_queue_head_init(&npinfo->txq);
 		INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
 
@@ -856,21 +895,24 @@ int netpoll_setup(struct netpoll *np)
 		}
 	}
 
-	if (!np->local_ip) {
-		rcu_read_lock();
-		in_dev = __in_dev_get_rcu(ndev);
+	if (!np->local_ip.ip) {
+		if (!np->ipv6) {
+			rcu_read_lock();
+			in_dev = __in_dev_get_rcu(ndev);
 
-		if (!in_dev || !in_dev->ifa_list) {
+
+			if (!in_dev || !in_dev->ifa_list) {
+				rcu_read_unlock();
+				np_err(np, "no IP address for %s, aborting\n",
+				       np->dev_name);
+				err = -EDESTADDRREQ;
+				goto put;
+			}
+
+			np->local_ip.ip = in_dev->ifa_list->ifa_local;
 			rcu_read_unlock();
-			np_err(np, "no IP address for %s, aborting\n",
-			       np->dev_name);
-			err = -EDESTADDRREQ;
-			goto put;
+			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
 		}
-
-		np->local_ip = in_dev->ifa_list->ifa_local;
-		rcu_read_unlock();
-		np_info(np, "local IP %pI4\n", &np->local_ip);
 	}
 
 	/* fill up the skb queue */
@@ -903,7 +945,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
 	struct netpoll_info *npinfo =
 			container_of(rcu_head, struct netpoll_info, rcu);
 
-	skb_queue_purge(&npinfo->arp_tx);
+	skb_queue_purge(&npinfo->neigh_tx);
 	skb_queue_purge(&npinfo->txq);
 
 	/* we can't call cancel_delayed_work_sync here, as we are in softirq */
-- 
1.7.7.6

^ permalink raw reply related

* Re: [PATCH net-next 0/8] Add complementary BPF conditional jump instructions
From: David Miller @ 2013-01-01  5:18 UTC (permalink / raw)
  To: eric.dumazet; +Cc: dborkman, netdev
In-Reply-To: <1357010942.21409.8948.camel@edumazet-glaptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 31 Dec 2012 19:29:02 -0800

> On Mon, 2012-12-31 at 14:37 -0800, David Miller wrote:
> 
>> Whilst I agree that adding NE jumps adds great value and closes a
>> serious gap, the rest can be synthesized by simply swapping the
>> arguments and using a comparison that does already exist.
>> 
>> Why isn't that sufficient?
> 
> I am afraid none of these patches is needed at all.
> 
> Swapping the jt/jf is plainly enough for the user land compiler.
> 
> libcap seems to do it already

Agreed.

^ permalink raw reply

* Re: [PATCH net-next 0/8] Add complementary BPF conditional jump instructions
From: Eric Dumazet @ 2013-01-01  3:29 UTC (permalink / raw)
  To: David Miller; +Cc: dborkman, netdev
In-Reply-To: <20121231.143715.1238174487756359071.davem@davemloft.net>

On Mon, 2012-12-31 at 14:37 -0800, David Miller wrote:

> Whilst I agree that adding NE jumps adds great value and closes a
> serious gap, the rest can be synthesized by simply swapping the
> arguments and using a comparison that does already exist.
> 
> Why isn't that sufficient?

I am afraid none of these patches is needed at all.

Swapping the jt/jf is plainly enough for the user land compiler.

libcap seems to do it already

# tcpdump -i lo 'len!=0 && ip6' -d
(000) ld       #pktlen
(001) jeq      #0x0             jt 5	jf 2
(002) ldh      [12]
(003) jeq      #0x86dd          jt 4	jf 5
(004) ret      #96
(005) ret      #0
# tcpdump -i lo 'len==0 && ip6' -d
(000) ld       #pktlen
(001) jeq      #0x0             jt 2	jf 5
(002) ldh      [12]
(003) jeq      #0x86dd          jt 4	jf 5
(004) ret      #96
(005) ret      #0

^ permalink raw reply

* Re: [PATCH net-next 5/8] net: bpf: add neq jump operations to bpf machine
From: Eric Dumazet @ 2013-01-01  3:25 UTC (permalink / raw)
  To: Daniel Borkmann; +Cc: davem, netdev
In-Reply-To: <ce1ddcbf8c0effcfa561b224630e3645504a6ad4.1356960070.git.dborkman@redhat.com>

On Mon, 2012-12-31 at 14:59 +0100, Daniel Borkmann wrote:
> This patch adds jump operations for neq (!=) that compare A
> with K resp. X in order to facilitate filter programming with
> conditional jumps, since currently only eq (==) is present in
> the BPF machine. For user-space filter programming / compilers,
> it might be good to also have this complementary operation.
> They don't need to be as ancillary, since they fit into the
> instruction encoding directly. Follow-up BPF JIT patches are
> welcomed.
> 
> Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
> ---
>  include/linux/filter.h      |  2 ++
>  include/uapi/linux/filter.h |  1 +
>  net/core/filter.c           | 14 ++++++++++++++
>  3 files changed, 17 insertions(+)
> 
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index 36630bc..256c01f 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -105,6 +105,8 @@ enum {
>  	BPF_S_JMP_JA,
>  	BPF_S_JMP_JEQ_K,
>  	BPF_S_JMP_JEQ_X,
> +	BPF_S_JMP_JNEQ_K,
> +	BPF_S_JMP_JNEQ_X,
>  	BPF_S_JMP_JGE_K,
>  	BPF_S_JMP_JGE_X,
>  	BPF_S_JMP_JGT_K,
> diff --git a/include/uapi/linux/filter.h b/include/uapi/linux/filter.h
> index 3ebcc2e..d909a6f 100644
> --- a/include/uapi/linux/filter.h
> +++ b/include/uapi/linux/filter.h
> @@ -80,6 +80,7 @@ struct sock_fprog {	/* Required for SO_ATTACH_FILTER. */
>  #define         BPF_JSET        0x40
>  #define         BPF_JLT         0x50
>  #define         BPF_JLE         0x60
> +#define         BPF_JNEQ        0x70
>  
>  #define BPF_SRC(code)   ((code) & 0x08)
>  #define         BPF_K           0x00
> diff --git a/net/core/filter.c b/net/core/filter.c
> index 2122eba..b360fb3 100644
> --- a/net/core/filter.c
> +++ b/net/core/filter.c
> @@ -228,6 +228,9 @@ unsigned int sk_run_filter(const struct sk_buff *skb,
>  		case BPF_S_JMP_JEQ_K:
>  			fentry += (A == K) ? fentry->jt : fentry->jf;
>  			continue;
> +		case BPF_S_JMP_JNEQ_K:
> +			fentry += (A != K) ? fentry->jt : fentry->jf;
> +			continue;
>  		case BPF_S_JMP_JSET_K:
>  			fentry += (A & K) ? fentry->jt : fentry->jf;
>  			continue;

This makes no sense at all to me, it seems kernel bloat.

The JNE instruction already exists.

You only have to take the JEQ (jt,jf) and swap the jt/jf targets.

^ permalink raw reply

* Re: [patch net-next 01/15] net: introduce upper device lists
From: Jiri Pirko @ 2013-01-01  1:04 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: netdev, davem, edumazet, bhutchings, faisal.latif, fbl, roland,
	sean.hefty, hal.rosenstock, fubar, andy, divy, jitendra.kalsaria,
	sony.chacko, linux-driver, kaber, ursula.braun, blaschka,
	schwidefsky, heiko.carstens, ebiederm, joe, amwang, nhorman,
	john.r.fastabend, pablo
In-Reply-To: <20121231112212.03319226@nehalam.linuxnetplumber.net>

Mon, Dec 31, 2012 at 08:22:12PM CET, shemminger@vyatta.com wrote:
>On Sun, 30 Dec 2012 12:58:08 +0100
>Jiri Pirko <jiri@resnulli.us> wrote:
>
>> This lists are supposed to serve for storing pointers to all upper devices.
>> Eventually it will replace dev->master pointer which is used for
>> bonding, bridge, team but it cannot be used for vlan, macvlan where
>> there might be multiple upper present. In case the upper link is
>> replacement for dev->master, it is marked with "master" flag.
>> 
>> New upper device list resolves this limitation. Also, the information
>> stored in lists is used for preventing looping setups like
>> "bond->somethingelse->samebond"
>> 
>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>
>I like the concept of knowing the topology of layered network devices.
>The name "upper device lists" is a little confusing to me.

Well, it's a list of devices "upper" to this one. Please provide more
suitable name alternative. I can't think of any, in fact I think "upper"
is pretty suitable.


>Also, the amount of additional data structures and book keeping
>seems more than needed; but not sure how to reduce it down to the
>least code.

Yep, that's it. I tried to make that as slim as possible. Trimming ideas
are very welcome.

>
>For simple case of detecting loops, just using existing master
>pointer is sufficient.
>       ethernet --> bonding --> bridge --+
>                       ^                 |
>                       |                 |
>                       +-----------------+
>This is the simple case of detecting if singularly linked list
>is a loop.
>
>The only device where multiple upper devices is possible seems
>to be macvlan. Could the special case code be limited to there?

Well, there are others, vlan for example. And the whole concept is to
make this uniform and generic, to avoid specific code for specific
drivers. And there are some usecases which can benefit from the upper
lists, like for example drivers which need to obtain l3 address info
(cxgb3, qlcnic, qeth).

But in any case, I doubt that this alternative approach will
lead to much smaller code footprint. I think it would be just more
messy.

^ permalink raw reply

* Re: [PATCH] tcp: split tcp_ecn sysctl knob to distinguish between IPv4 and IPv6
From: Hannes Frederic Sowa @ 2012-12-31 23:58 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20121231140538.6e55c82d@nehalam.linuxnetplumber.net>

On Mon, Dec 31, 2012 at 02:05:38PM -0800, Stephen Hemminger wrote:
> On Mon, 31 Dec 2012 18:35:33 +0100
> Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:
> 
> > ECN could be more reliable when used with IPv6 (I don't have proofs). For
> > people who want to try ECN with IPv6 but still have problems connecting
> > to destinations because of broken IPv4 routers this switch allows one
> > to enable ECN just for IPv6.
> > 
> > Perhaps ECN could be enabled by default in future.
> > 
> > Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> 
> Any new or modified sysctl should be documented in:
>   Documentation/networking/ip-sysctl.txt

Ack. I'll wait a bit for further feedback and will submit a -v2 with updated
documentation.

^ permalink raw reply

* Re: [PATCH] tcp: split tcp_ecn sysctl knob to distinguish between IPv4 and IPv6
From: Hannes Frederic Sowa @ 2012-12-31 23:48 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20121231140412.7dee9821@nehalam.linuxnetplumber.net>

On Mon, Dec 31, 2012 at 02:04:12PM -0800, Stephen Hemminger wrote:
> On Mon, 31 Dec 2012 18:35:33 +0100
> Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:
> 
> > diff --git a/include/net/sock.h b/include/net/sock.h
> > index 182ca99..aa3c30e 100644
> > --- a/include/net/sock.h
> > +++ b/include/net/sock.h
> > @@ -944,6 +944,7 @@ struct proto {
> >  	int			*sysctl_rmem;
> >  	int			max_header;
> >  	bool			no_autobind;
> > +	int			ecn;
> >  
> Why isn't this a bool?

It is a tristate: disable ecn(0), request ecn(1) and accept ecn(2).

^ permalink raw reply

* Re: [PATCH] poll: prevent missed events if _qproc is NULL
From: Eric Wong @ 2012-12-31 23:24 UTC (permalink / raw)
  To: linux-kernel
  Cc: Hans Verkuil, Jiri Olsa, Jonathan Corbet, Al Viro, Davide Libenzi,
	Hans de Goede, Mauro Carvalho Chehab, David Miller, Eric Dumazet,
	Andrew Morton, Linus Torvalds, Andreas Voellmy,
	Junchang(Jason) Wang, netdev, linux-fsdevel
In-Reply-To: <1356960060-1263-1-git-send-email-normalperson@yhbt.net>

Eric Wong <normalperson@yhbt.net> wrote:
> This patch seems to fix my issue with ppoll() being stuck on my
> SMP machine: http://article.gmane.org/gmane.linux.file-systems/70414

OK, it doesn't fix my issue, but it seems to make it harder-to-hit...

> The change to sock_poll_wait() in
> commit 626cf236608505d376e4799adb4f7eb00a8594af
>   (poll: add poll_requested_events() and poll_does_not_wait() functions)
> seems to have allowed additional cases where the SMP memory barrier
> is not issued before checking for readiness.
> 
> In my case, this affects the select()-family of functions
> which register descriptors once and set _qproc to NULL before
> checking events again (after poll_schedule_timeout() returns).
> The set_mb() barrier in poll_schedule_timeout() appears to be
> insufficient on my SMP x86-64 machine (as it's only an xchg()).
> 
> This may also be related to the epoll issue described by
> Andreas Voellmy in http://thread.gmane.org/gmane.linux.kernel/1408782/

However, I believe my patch will still fix Andreas' issue with epoll
due to how ep_modify() uses a NULL qproc when calling ->poll().

(I've never been able to reproduce Andreas' issue on my 4-core system,
 but he's been hitting it since 3.4 (at least))

^ permalink raw reply

* Re: [PATCH net-next 0/8] Add complementary BPF conditional jump instructions
From: David Miller @ 2012-12-31 22:37 UTC (permalink / raw)
  To: dborkman; +Cc: netdev
In-Reply-To: <cover.1356960070.git.dborkman@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Mon, 31 Dec 2012 14:59:40 +0100

> This set adds adds jump operations for lt (<), le (<=), ne (!=) that
> compare A with K resp. X in order to facilitate filter programming
> with conditional jumps, as also available in McCanne et. al's BPF+
> paper (``BPF+: Exploiting Global Data-flow Optimization in a Generalized
> Packet Filter Architecture'').
> 
> Also, follow-up BPF JIT implementations for x86, Sparc and PowerPC
> are added in this set.

Whilst I agree that adding NE jumps adds great value and closes a
serious gap, the rest can be synthesized by simply swapping the
arguments and using a comparison that does already exist.

Why isn't that sufficient?

^ permalink raw reply

* Re: [PATCH] net: fix checking boundary of valid vlan id
From: Glen Turner @ 2012-12-31 22:30 UTC (permalink / raw)
  To: Benny Amorsen; +Cc: Florian Westphal, akong, netdev, davem
In-Reply-To: <m3fw2mp2lh.fsf@ursa.amorsen.dk>


On 01/01/2013, at 3:42 AM, Benny Amorsen wrote:

> Glen Turner <gdt@gdt.id.au> writes:
> 
>> It may be a valid VLAN ID, or it may not. The meaning of FFF is
>> reserved for vendor use, which doesn't preclude a vendor using it as a
>> (non-interoperable) VLAN identifier. Many vendor's products treat 4096
>> as they do any other VID.
> 
> I may be missing something vital, but 4096 is 0x1000 not 0xFFF? 4095 is
> reserved and 0 means "treat as if the packet was untagged". 4096 is
> impossible, there are only 12 bit and the encoding is AFAIK bog standard
> binary.

Yep, I've failed at hex math. 0xfff = 4095 is the maximal VID value, and is the one reserved for vendor use.
Which means that the patch checking values 1 to 4095 is correct.

My apologies,
glen

^ permalink raw reply

* Re: [PATCH RFC 15/15] via-rhine: add helper (reduce type-unsafe void * assignments).
From: David Miller @ 2012-12-31 22:21 UTC (permalink / raw)
  To: andi; +Cc: andim2, rl, netdev, romieu
In-Reply-To: <1356967549-5056-16-git-send-email-andi@lisas.de>

From: Andreas Mohr <andi@lisas.de>
Date: Mon, 31 Dec 2012 16:25:49 +0100

> From: Andreas Mohr <andim2@users.sf.net>
> 
> Signed-off-by: Andreas Mohr <andim2@users.sf.net>

This is of zero value.

It is just as likely one would forget to use the helper as it would be
to assign pci_get_drvdata() to a pointer of the wrong type.

^ permalink raw reply

* Re: [PATCH v2 net-next] team: add ethtool support
From: Ben Hutchings @ 2012-12-31 22:16 UTC (permalink / raw)
  To: Flavio Leitner; +Cc: netdev, Jiri Pirko
In-Reply-To: <1356835053-25602-1-git-send-email-fbl@redhat.com>

On Sun, 2012-12-30 at 00:37 -0200, Flavio Leitner wrote:
> This patch adds few ethtool operations to team driver.
> 
> Signed-off-by: Flavio Leitner <fbl@redhat.com>
> ---
> v2 - removed generic statistics from ethtool
> 
>  drivers/net/team/team.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
> index ad86660..7665a088 100644
> --- a/drivers/net/team/team.c
> +++ b/drivers/net/team/team.c
[...]
> +static void team_ethtool_get_drvinfo(struct net_device *dev,
> +				     struct ethtool_drvinfo *drvinfo)
> +{
> +	strncpy(drvinfo->driver, DRV_NAME, 32);
> +	strncpy(drvinfo->version, UTS_RELEASE, 32);
> +}
[...]

These must be null-terminated, so use strlcpy() not strncpy().

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply

* Re: [PATCH] tcp: split tcp_ecn sysctl knob to distinguish between IPv4 and IPv6
From: Stephen Hemminger @ 2012-12-31 22:05 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: netdev
In-Reply-To: <20121231173532.GA11700@order.stressinduktion.org>

On Mon, 31 Dec 2012 18:35:33 +0100
Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:

> ECN could be more reliable when used with IPv6 (I don't have proofs). For
> people who want to try ECN with IPv6 but still have problems connecting
> to destinations because of broken IPv4 routers this switch allows one
> to enable ECN just for IPv6.
> 
> Perhaps ECN could be enabled by default in future.
> 
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>

Any new or modified sysctl should be documented in:
  Documentation/networking/ip-sysctl.txt

^ permalink raw reply

* Re: [PATCH] tcp: split tcp_ecn sysctl knob to distinguish between IPv4 and IPv6
From: Stephen Hemminger @ 2012-12-31 22:04 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: netdev
In-Reply-To: <20121231173532.GA11700@order.stressinduktion.org>

On Mon, 31 Dec 2012 18:35:33 +0100
Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:

> diff --git a/include/net/sock.h b/include/net/sock.h
> index 182ca99..aa3c30e 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -944,6 +944,7 @@ struct proto {
>  	int			*sysctl_rmem;
>  	int			max_header;
>  	bool			no_autobind;
> +	int			ecn;
>  
Why isn't this a bool?

^ permalink raw reply

* [PATCH] vxlan: allow live mac address change
From: Stephen Hemminger @ 2012-12-31 22:00 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

The VXLAN pseudo-device doesn't care if the mac address changes
when device is up.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--- a/drivers/net/vxlan.c	2012-12-27 22:30:53.630796042 -0800
+++ b/drivers/net/vxlan.c	2012-12-31 10:46:25.435321912 -0800
@@ -1191,6 +1191,7 @@ static void vxlan_setup(struct net_devic
 
 	dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
 	dev->priv_flags	&= ~IFF_XMIT_DST_RELEASE;
+	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
 	spin_lock_init(&vxlan->hash_lock);
 

^ permalink raw reply

* Re: [patch net-next 01/15] net: introduce upper device lists
From: Stephen Hemminger @ 2012-12-31 19:22 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, edumazet, bhutchings, faisal.latif, fbl, roland,
	sean.hefty, hal.rosenstock, fubar, andy, divy, jitendra.kalsaria,
	sony.chacko, linux-driver, kaber, ursula.braun, blaschka,
	schwidefsky, heiko.carstens, ebiederm, joe, amwang, nhorman,
	john.r.fastabend, pablo
In-Reply-To: <1356868702-8144-2-git-send-email-jiri@resnulli.us>

On Sun, 30 Dec 2012 12:58:08 +0100
Jiri Pirko <jiri@resnulli.us> wrote:

> This lists are supposed to serve for storing pointers to all upper devices.
> Eventually it will replace dev->master pointer which is used for
> bonding, bridge, team but it cannot be used for vlan, macvlan where
> there might be multiple upper present. In case the upper link is
> replacement for dev->master, it is marked with "master" flag.
> 
> New upper device list resolves this limitation. Also, the information
> stored in lists is used for preventing looping setups like
> "bond->somethingelse->samebond"
> 
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>

I like the concept of knowing the topology of layered network devices.
The name "upper device lists" is a little confusing to me.
Also, the amount of additional data structures and book keeping
seems more than needed; but not sure how to reduce it down to the
least code.

For simple case of detecting loops, just using existing master
pointer is sufficient.
       ethernet --> bonding --> bridge --+
                       ^                 |
                       |                 |
                       +-----------------+
This is the simple case of detecting if singularly linked list
is a loop.

The only device where multiple upper devices is possible seems
to be macvlan. Could the special case code be limited to there?

^ permalink raw reply

* [PATCH] tcp: split tcp_ecn sysctl knob to distinguish between IPv4 and IPv6
From: Hannes Frederic Sowa @ 2012-12-31 17:35 UTC (permalink / raw)
  To: netdev

ECN could be more reliable when used with IPv6 (I don't have proofs). For
people who want to try ECN with IPv6 but still have problems connecting
to destinations because of broken IPv4 routers this switch allows one
to enable ECN just for IPv6.

Perhaps ECN could be enabled by default in future.

Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 include/net/sock.h         | 1 +
 include/net/tcp.h          | 8 +++++---
 net/ipv4/syncookies.c      | 6 ++++--
 net/ipv4/sysctl_net_ipv4.c | 2 +-
 net/ipv4/tcp_input.c       | 2 --
 net/ipv4/tcp_ipv4.c        | 3 ++-
 net/ipv4/tcp_output.c      | 2 +-
 net/ipv6/syncookies.c      | 3 ++-
 net/ipv6/sysctl_net_ipv6.c | 8 ++++++++
 net/ipv6/tcp_ipv6.c        | 4 +++-
 10 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 182ca99..aa3c30e 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -944,6 +944,7 @@ struct proto {
 	int			*sysctl_rmem;
 	int			max_header;
 	bool			no_autobind;
+	int			ecn;
 
 	struct kmem_cache	*slab;
 	unsigned int		obj_size;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index aed42c7..1202a6d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -266,7 +266,6 @@ extern int sysctl_tcp_abort_on_overflow;
 extern int sysctl_tcp_max_orphans;
 extern int sysctl_tcp_fack;
 extern int sysctl_tcp_reordering;
-extern int sysctl_tcp_ecn;
 extern int sysctl_tcp_dsack;
 extern int sysctl_tcp_wmem[3];
 extern int sysctl_tcp_rmem[3];
@@ -351,6 +350,7 @@ static inline bool tcp_synq_no_recent_overflow(const struct sock *sk)
 }
 
 extern struct proto tcp_prot;
+extern struct proto tcpv6_prot;
 
 #define TCP_INC_STATS(net, field)	SNMP_INC_STATS((net)->mib.tcp_statistics, field)
 #define TCP_INC_STATS_BH(net, field)	SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field)
@@ -504,7 +504,8 @@ static inline __u32 cookie_v4_init_sequence(struct sock *sk,
 #endif
 
 extern __u32 cookie_init_timestamp(struct request_sock *req);
-extern bool cookie_check_timestamp(struct tcp_options_received *opt, bool *);
+extern bool cookie_check_timestamp(struct tcp_options_received *opt,
+				int sysctl_tcp_ecn, bool *ecn_ok);
 
 /* From net/ipv6/syncookies.c */
 extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb);
@@ -728,7 +729,8 @@ struct tcp_skb_cb {
  * notifications, we disable TCP ECN negociation.
  */
 static inline void
-TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb)
+TCP_ECN_create_request(struct request_sock *req,
+		const struct sk_buff *skb, int sysctl_tcp_ecn)
 {
 	const struct tcphdr *th = tcp_hdr(skb);
 
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index b236ef0..64dbfc5 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -232,7 +232,8 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
  *
  * return false if we decode an option that should not be.
  */
-bool cookie_check_timestamp(struct tcp_options_received *tcp_opt, bool *ecn_ok)
+bool cookie_check_timestamp(struct tcp_options_received *tcp_opt,
+			int sysctl_tcp_ecn, bool *ecn_ok)
 {
 	/* echoed timestamp, lowest bits contain options */
 	u32 options = tcp_opt->rcv_tsecr & TSMASK;
@@ -278,6 +279,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	struct rtable *rt;
 	__u8 rcv_wscale;
 	bool ecn_ok = false;
+	int sysctl_tcp_ecn = sk->sk_prot->ecn;
 	struct flowi4 fl4;
 
 	if (!sysctl_tcp_syncookies || !th->ack || th->rst)
@@ -295,7 +297,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 	memset(&tcp_opt, 0, sizeof(tcp_opt));
 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
 
-	if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+	if (!cookie_check_timestamp(&tcp_opt, sysctl_tcp_ecn, &ecn_ok))
 		goto out;
 
 	ret = NULL;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index d84400b..f7aac98 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -539,7 +539,7 @@ static struct ctl_table ipv4_table[] = {
 	},
 	{
 		.procname	= "tcp_ecn",
-		.data		= &sysctl_tcp_ecn,
+		.data		= &tcp_prot.ecn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a28e4db..38e1184 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -81,8 +81,6 @@ int sysctl_tcp_sack __read_mostly = 1;
 int sysctl_tcp_fack __read_mostly = 1;
 int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH;
 EXPORT_SYMBOL(sysctl_tcp_reordering);
-int sysctl_tcp_ecn __read_mostly = 2;
-EXPORT_SYMBOL(sysctl_tcp_ecn);
 int sysctl_tcp_dsack __read_mostly = 1;
 int sysctl_tcp_app_win __read_mostly = 31;
 int sysctl_tcp_adv_win_scale __read_mostly = 1;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 54139fa..32e012a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1568,7 +1568,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 		goto drop_and_free;
 
 	if (!want_cookie || tmp_opt.tstamp_ok)
-		TCP_ECN_create_request(req, skb);
+		TCP_ECN_create_request(req, skb, tcp_prot.ecn);
 
 	if (want_cookie) {
 		isn = cookie_v4_init_sequence(sk, skb, &req->mss);
@@ -2874,6 +2874,7 @@ struct proto tcp_prot = {
 	.rsk_prot		= &tcp_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
 	.no_autobind		= true,
+	.ecn			= 2,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 5d45159..0c75961 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -314,7 +314,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	tp->ecn_flags = 0;
-	if (sysctl_tcp_ecn == 1) {
+	if (sk->sk_prot->ecn == 1) {
 		TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
 		tp->ecn_flags = TCP_ECN_OK;
 	}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 4016197..ce19227 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -163,6 +163,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	struct dst_entry *dst;
 	__u8 rcv_wscale;
 	bool ecn_ok = false;
+	int sysctl_tcp_ecn = sk->sk_prot->ecn;
 
 	if (!sysctl_tcp_syncookies || !th->ack || th->rst)
 		goto out;
@@ -179,7 +180,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	memset(&tcp_opt, 0, sizeof(tcp_opt));
 	tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
 
-	if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
+	if (!cookie_check_timestamp(&tcp_opt, sysctl_tcp_ecn, &ecn_ok))
 		goto out;
 
 	ret = NULL;
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index e85c48b..a2e764f 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -15,6 +15,7 @@
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
+#include <net/tcp.h>
 
 static ctl_table ipv6_table_template[] = {
 	{
@@ -24,6 +25,13 @@ static ctl_table ipv6_table_template[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec
 	},
+	{
+		.procname	= "tcp_ecn",
+		.data		= &tcpv6_prot.ecn,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
 	{ }
 };
 
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 93825dd..98bd8a3 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1027,7 +1027,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	treq->rmt_addr = ipv6_hdr(skb)->saddr;
 	treq->loc_addr = ipv6_hdr(skb)->daddr;
 	if (!want_cookie || tmp_opt.tstamp_ok)
-		TCP_ECN_create_request(req, skb);
+		TCP_ECN_create_request(req, skb, tcpv6_prot.ecn);
 
 	treq->iif = sk->sk_bound_dev_if;
 
@@ -1955,6 +1955,7 @@ struct proto tcpv6_prot = {
 	.rsk_prot		= &tcp6_request_sock_ops,
 	.h.hashinfo		= &tcp_hashinfo,
 	.no_autobind		= true,
+	.ecn			= 2,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
@@ -1963,6 +1964,7 @@ struct proto tcpv6_prot = {
 	.proto_cgroup		= tcp_proto_cgroup,
 #endif
 };
+EXPORT_SYMBOL(tcpv6_prot);
 
 static const struct inet6_protocol tcpv6_protocol = {
 	.early_demux	=	tcp_v6_early_demux,

^ permalink raw reply related

* Re: [PATCH] net: fix checking boundary of valid vlan id
From: Benny Amorsen @ 2012-12-31 17:12 UTC (permalink / raw)
  To: Glen Turner; +Cc: Florian Westphal, akong, netdev, davem
In-Reply-To: <186CBD58-5106-4FCD-8C73-E4EC84C3A303@gdt.id.au>

Glen Turner <gdt@gdt.id.au> writes:

> It may be a valid VLAN ID, or it may not. The meaning of FFF is
> reserved for vendor use, which doesn't preclude a vendor using it as a
> (non-interoperable) VLAN identifier. Many vendor's products treat 4096
> as they do any other VID.

I may be missing something vital, but 4096 is 0x1000 not 0xFFF? 4095 is
reserved and 0 means "treat as if the packet was untagged". 4096 is
impossible, there are only 12 bit and the encoding is AFAIK bog standard
binary.


/Benny

^ permalink raw reply

* [PATCH net-next 6/8] x86: bpf_jit_comp: add JMP_NEQ instructions for BPF JIT
From: Daniel Borkmann @ 2012-12-31 17:00 UTC (permalink / raw)
  To: davem; +Cc: netdev, Eric Dumazet
In-Reply-To: <cover.1356960070.git.dborkman@redhat.com>

This patch is a follow-up for patch "net: bpf: add neq jump
operations to bpf machine" that implements BPF x86 JIT parts
for the BPF JMP_NEQ operation.

Cc: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
 arch/x86/net/bpf_jit_comp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 6d6a4ce..bd10c83 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -587,12 +587,14 @@ common_load_ind:		seen |= SEEN_DATAREF | SEEN_XREG;
 			COND_SEL(BPF_S_JMP_JLT_K, X86_JB, X86_JAE);
 			COND_SEL(BPF_S_JMP_JLE_K, X86_JBE, X86_JA);
 			COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE);
+			COND_SEL(BPF_S_JMP_JNEQ_K,X86_JNE, X86_JE);
 			COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE);
 			COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE);
 			COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB);
 			COND_SEL(BPF_S_JMP_JLT_X, X86_JB, X86_JAE);
 			COND_SEL(BPF_S_JMP_JLE_X, X86_JBE, X86_JA);
 			COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE);
+			COND_SEL(BPF_S_JMP_JNEQ_X,X86_JNE, X86_JE);
 			COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE);
 
 cond_branch:			f_offset = addrs[i + filter[i].jf] - addrs[i];
@@ -610,6 +612,7 @@ cond_branch:			f_offset = addrs[i + filter[i].jf] - addrs[i];
 				case BPF_S_JMP_JLT_X:
 				case BPF_S_JMP_JLE_X:
 				case BPF_S_JMP_JEQ_X:
+				case BPF_S_JMP_JNEQ_X:
 					seen |= SEEN_XREG;
 					EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */
 					break;
@@ -618,6 +621,7 @@ cond_branch:			f_offset = addrs[i + filter[i].jf] - addrs[i];
 					EMIT2(0x85, 0xd8); /* test %ebx,%eax */
 					break;
 				case BPF_S_JMP_JEQ_K:
+				case BPF_S_JMP_JNEQ_K:
 					if (K == 0) {
 						EMIT2(0x85, 0xc0); /* test   %eax,%eax */
 						break;
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH RFC 11/15] via-rhine: WOL: separate WOL configuration (and its logging).
From: Andreas Mohr @ 2012-12-31 15:25 UTC (permalink / raw)
  To: andim2; +Cc: Roger Luethi, netdev, Francois Romieu
In-Reply-To: <1356967549-5056-1-git-send-email-andi@lisas.de>

From: Andreas Mohr <andim2@users.sf.net>

Add helper rhine_power_state_configure().

Signed-off-by: Andreas Mohr <andim2@users.sf.net>
---
 drivers/net/ethernet/via/via-rhine.c |  129 +++++++++++++++++++++-------------
 1 files changed, 80 insertions(+), 49 deletions(-)

diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 7e13d50..8950eb0 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -562,6 +562,81 @@ static void rhine_ack_events(struct rhine_private *rp, u32 mask)
 	mmiowb();
 }
 
+/* Configures ACPI D0..D3 on card side. */
+static void
+rhine_power_state_configure(struct rhine_private *rp, u8 pci_state)
+{
+	void __iomem *ioaddr = rp->base;
+	u8 other_bits;
+	WARN_ON(!((pci_state >= 0) && (pci_state <= 3)));
+
+	other_bits = ioread8(ioaddr + StickyHW) & 0xFC;
+	iowrite8(other_bits | pci_state, ioaddr + StickyHW);
+}
+
+static inline void
+rhine_wol_configure(struct net_device *dev, u16 *wolstat_out)
+{
+	struct rhine_private *rp = netdev_priv(dev);
+	void __iomem *ioaddr = rp->base;
+	u16 wolstat = 0;
+
+	/* Make sure chip is in power state D0 */
+	rhine_power_state_configure(rp, 0);
+
+	/* Disable "force PME-enable" */
+	iowrite8(0x80, ioaddr + WOLcgClr);
+
+	/* Clear power-event config bits (WOL) */
+	iowrite8(0xFF, ioaddr + WOLcrClr);
+	/* More recent cards can manage two additional patterns */
+	if (rp->quirks & rq6patterns)
+		iowrite8(0x03, ioaddr + WOLcrClr1);
+
+	/* Save power-event status bits */
+	wolstat = ioread8(ioaddr + PwrcsrSet);
+	if (rp->quirks & rq6patterns)
+		wolstat |= (ioread8(ioaddr + PwrcsrSet1) & 0x03) << 8;
+
+	/* Clear power-event status bits */
+	iowrite8(0xFF, ioaddr + PwrcsrClr);
+	if (rp->quirks & rq6patterns)
+		iowrite8(0x03, ioaddr + PwrcsrClr1);
+
+	if (wolstat_out)
+		*wolstat_out = wolstat;
+}
+
+static inline void
+rhine_wol_log_wakeup_reason(struct net_device *dev, u16 wolstat)
+{
+	if (wolstat) {
+		const char *reason;
+		switch (wolstat) {
+		case WOLmagic:
+			reason = "Magic packet";
+			break;
+		case WOLlnkon:
+			reason = "Link went up";
+			break;
+		case WOLlnkoff:
+			reason = "Link went down";
+			break;
+		case WOLucast:
+			reason = "Unicast packet";
+			break;
+		case WOLbmcast:
+			reason = "Multicast/broadcast packet";
+			break;
+		default:
+			reason = "Unknown";
+			break;
+		}
+		netdev_info(dev, "Woke system up. Reason: %s\n",
+			    reason);
+	}
+}
+
 /*
  * Get power related registers into sane state.
  * Notify user about past WOL event.
@@ -569,56 +644,12 @@ static void rhine_ack_events(struct rhine_private *rp, u32 mask)
 static void rhine_power_init(struct net_device *dev)
 {
 	struct rhine_private *rp = netdev_priv(dev);
-	void __iomem *ioaddr = rp->base;
-	u16 wolstat;
 
 	if (rp->quirks & rqHaveWOL) {
-		/* Make sure chip is in power state D0 */
-		iowrite8(ioread8(ioaddr + StickyHW) & 0xFC, ioaddr + StickyHW);
-
-		/* Disable "force PME-enable" */
-		iowrite8(0x80, ioaddr + WOLcgClr);
-
-		/* Clear power-event config bits (WOL) */
-		iowrite8(0xFF, ioaddr + WOLcrClr);
-		/* More recent cards can manage two additional patterns */
-		if (rp->quirks & rq6patterns)
-			iowrite8(0x03, ioaddr + WOLcrClr1);
-
-		/* Save power-event status bits */
-		wolstat = ioread8(ioaddr + PwrcsrSet);
-		if (rp->quirks & rq6patterns)
-			wolstat |= (ioread8(ioaddr + PwrcsrSet1) & 0x03) << 8;
-
-		/* Clear power-event status bits */
-		iowrite8(0xFF, ioaddr + PwrcsrClr);
-		if (rp->quirks & rq6patterns)
-			iowrite8(0x03, ioaddr + PwrcsrClr1);
-
-		if (wolstat) {
-			char *reason;
-			switch (wolstat) {
-			case WOLmagic:
-				reason = "Magic packet";
-				break;
-			case WOLlnkon:
-				reason = "Link went up";
-				break;
-			case WOLlnkoff:
-				reason = "Link went down";
-				break;
-			case WOLucast:
-				reason = "Unicast packet";
-				break;
-			case WOLbmcast:
-				reason = "Multicast/broadcast packet";
-				break;
-			default:
-				reason = "Unknown";
-			}
-			netdev_info(dev, "Woke system up. Reason: %s\n",
-				    reason);
-		}
+		u16 wolstat;
+		rhine_wol_configure(dev, &wolstat);
+
+		rhine_wol_log_wakeup_reason(dev, wolstat);
 	}
 }
 
@@ -2325,7 +2356,7 @@ rhine_shutdown_and_keep_wol(struct pci_dev *pdev)
 	spin_unlock(&rp->lock);
 
 	if (system_state == SYSTEM_POWER_OFF && !avoid_D3) {
-		iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
+		rhine_power_state_configure(rp, 3);
 
 		pci_wake_from_d3(pdev, true);
 		pci_set_power_state(pdev, PCI_D3hot);
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH RFC 13/15] via-rhine: misc. cleanup.
From: Andreas Mohr @ 2012-12-31 15:25 UTC (permalink / raw)
  To: andim2; +Cc: Roger Luethi, netdev, Francois Romieu
In-Reply-To: <1356967549-5056-1-git-send-email-andi@lisas.de>

From: Andreas Mohr <andim2@users.sf.net>

Several register values remained open-coded - use their defines instead.
Improve register define grouping.
Improve log messages.
Add comments.

Signed-off-by: Andreas Mohr <andim2@users.sf.net>
---
 drivers/net/ethernet/via/via-rhine.c |   92 ++++++++++++++++++++++++++++------
 1 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 90d109a..984f056 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -27,6 +27,34 @@
 	http://www.scyld.com/network/via-rhine.html
 	[link no longer provides useful info -jgarzik]
 
+
+	This driver should get some whack: several handlers
+	seem to have their concerns intermingled. Rather,
+	functions should be grouped into generically usable micro handlers
+	(I/O access concerns, WOL handling, MII, etc. - with card specifics
+	properly dealt with via suitable *internal* abstraction as needed)
+	which are then being invoked by *specifically-purposed*
+	high-level, system-side operational handlers
+	on an as-needed-in-this-scope basis.
+	But that's a very painful issue with too many drivers, unfortunately.
+	Some rather unrelated handling within a function may easily end up
+	becoming an unwanted "side effect" once other use cases appear,
+	with rather unclear grouping of concerns being the root cause :(
+	Or, to put it bluntly: you're in the wild here - an uncontrollable mass
+	of unwashed developers hacking away at things
+	(and breaking things willy-nilly whenever getting confused
+	about intentions of original implementation!!),
+	with the only marginal chance of getting this avoided being
+	to better get your core implementation, layering
+	and especially component naming right (well, DAMN RIGHT).
+
+	TODO: one example would be clean encapsulation of I/O register access -
+	such helper functions would optionally allow keeping a watch on access
+	to extended registers unsupported by earlier revs.
+
+	TODO list:
+		(see TODO annotations at future work sites below
+		 [more hunk-friendly])
 */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -299,18 +327,23 @@ enum register_offsets {
 	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, PCIBusConfig1=0x6F,
 	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
 	ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
-	RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
+	RxMissed = 0x7C, RxCRCErrs = 0x7E,
+	/*** Extended register range (newer revs only) starts here ***/
+	MiscCmd = 0x81,
 	StickyHW=0x83, IntrStatus2=0x84,
-	CamMask=0x88, CamCon=0x92, CamAddr=0x93,
-	WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4,
-	WOLcrClr1=0xA6, WOLcgClr=0xA7,
-	PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
+	CamMask = 0x88, CamCon = 0x92, CamAddr = 0x93,
+	/* various flag set/clear registers */
+	WOLcrSet = 0xA0, PwcfgSet = 0xA1, WOLcgSet = 0xA3,
+	WOLcrClr = 0xA4, WOLcrClr1 = 0xA6, WOLcgClr = 0xA7,
+	PwrcsrSet = 0xA8, PwrcsrSet1 = 0xA9,
+	PwrcsrClr = 0xAC, PwrcsrClr1 = 0xAD,
 };
 
 /* Bits in ConfigD */
 enum backoff_bits {
-	BackOptional=0x01, BackModify=0x02,
-	BackCaptureEffect=0x04, BackRandom=0x08
+	BackOptional = 0x01, BackModify = 0x02,
+	BackCaptureEffect = 0x04, BackRandom = 0x08,
+	MMIOEnable = 0x80
 };
 
 /* Bits in the TxConfig (TCR) register */
@@ -688,7 +721,7 @@ static void enable_mmio(long pioaddr, u32 quirks)
 		n = inb(pioaddr + ConfigA) | 0x20;
 		outb(n, pioaddr + ConfigA);
 	} else {
-		n = inb(pioaddr + ConfigD) | 0x80;
+		n = inb(pioaddr + ConfigD) | MMIOEnable;
 		outb(n, pioaddr + ConfigD);
 	}
 }
@@ -759,6 +792,18 @@ static void rhine_poll(struct net_device *dev)
 	struct rhine_private *rp = netdev_priv(dev);
 	const int irq = rp->pdev->irq;
 
+	/*
+	 * TODO: this "weird" section (passes in a "fake" irq number
+	 * param, etc.) here looks like some functionality inversion
+	 * is in order (i.e., probably the non-irq related IRQ handler core
+	 * should be moved into helper function, which then is the one
+	 * to *cleanly* be called from here, too!)
+	 * OTOH maybe it's a specific requirement to disable IRQ
+	 * and then do call the real handler impl instead -
+	 * but then a comment should have been provided,
+	 * to explain specifics of why we're manually calling
+	 * into the actual interrupt handler...
+	 */
 	disable_irq(irq);
 	rhine_interrupt(irq, dev);
 	enable_irq(irq);
@@ -771,7 +816,7 @@ static void rhine_kick_tx_threshold(struct rhine_private *rp)
 		void __iomem *ioaddr = rp->base;
 
 		rp->tx_thresh += 0x20;
-		BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig);
+		BYTE_REG_BITS_SET(rp->tx_thresh, TCR_RTSF, ioaddr + TxConfig);
 	}
 }
 
@@ -1044,6 +1089,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	rhine_power_init(dev);
 	rhine_hw_init(dev, rp->pioaddr);
 
+	/* Do bootstrap-only init steps (initial dev_addr, phy_id) */
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i);
 
@@ -1058,7 +1104,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* For Rhine-I/II, phy_id is loaded from EEPROM */
 	if (!phy_id)
-		phy_id = ioread8(ioaddr + 0x6C);
+		phy_id = ioread8(ioaddr + MIIPhyAddr);
 
 	spin_lock_init(&rp->lock);
 	mutex_init(&rp->task_lock);
@@ -1097,6 +1143,10 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	pci_set_drvdata(pdev, dev);
 
+	/* FIXME!! I really *don't* think that this stuff has any business
+	 * being open-coded in probe() rather than being a helper possibly
+	 * called from multiple sites (resume, etc.) - netif_carrier_on()!!
+	 */
 	{
 		u16 mii_cmd;
 		int mii_status = mdio_read(dev, phy_id, 1);
@@ -1119,8 +1169,10 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 	rp->mii_if.phy_id = phy_id;
+
+	/* Use this occasion to announce avoid_D3 state, too. */
 	if (avoid_D3)
-		netif_info(rp, probe, dev, "No D3 power state at shutdown\n");
+		netif_info(rp, probe, dev, "Will avoid entering D3 power state at shutdown\n");
 
 	return 0;
 
@@ -1499,8 +1551,10 @@ static void init_registers(struct net_device *dev)
 
 	/* Initialize other registers. */
 	iowrite16(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
+	/* Seems that it's DMA Length reg (select "store & forward" option). */
+
 	/* Configure initial FIFO thresholds. */
-	iowrite8(0x20, ioaddr + TxConfig);
+	iowrite8(TCR_RTFT0, ioaddr + TxConfig);
 	rp->tx_thresh = 0x20;
 	rp->rx_thresh = 0x60;		/* Written in rhine_set_rx_mode(). */
 
@@ -1543,7 +1597,7 @@ static void rhine_disable_linkmon(struct rhine_private *rp)
 	iowrite8(0, ioaddr + MIICmd);
 
 	if (rp->quirks & rqRhineI) {
-		iowrite8(0x01, ioaddr + MIIRegAddr);	// MII_BMSR
+		iowrite8(MII_BMSR, ioaddr + MIIRegAddr);
 
 		/* Can be called from ISR. Evil. */
 		mdelay(1);
@@ -2316,11 +2370,11 @@ static int rhine_close(struct net_device *dev)
 	napi_disable(&rp->napi);
 	netif_stop_queue(dev);
 
-	netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n",
-		  ioread16(ioaddr + ChipCmd));
+	netif_dbg(rp, ifdown, dev, "%s() Shutting down ethercard, status was %04x\n",
+		  __func__, ioread16(ioaddr + ChipCmd));
 
 	/* Switch to loopback mode to avoid hardware races. */
-	iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
+	iowrite8(rp->tx_thresh | TCR_LB0, ioaddr + TxConfig);
 
 	rhine_irq_disable(rp);
 
@@ -2369,6 +2423,11 @@ rhine_shutdown_and_keep_wol(struct pci_dev *pdev)
 
 	spin_lock(&rp->lock);
 
+	/*
+	 * We are able to poke single bits in sequence
+	 * (due to registers being organised as a set/clear combo).
+	 */
+
 	if (rp->wolopts & WAKE_MAGIC) {
 		iowrite8(WOLmagic, ioaddr + WOLcrSet);
 		/*
@@ -2404,6 +2463,7 @@ rhine_shutdown_and_keep_wol(struct pci_dev *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/* TODO: implement full runtime pm, e.g. as done by r8169.c */
 static int rhine_suspend(struct device *device)
 {
 	struct pci_dev *pdev = to_pci_dev(device);
-- 
1.7.2.5

^ permalink raw reply related

* [PATCH RFC 00/15] via-rhine: fix resume, cleanup, eth ops (regs)
From: Andreas Mohr @ 2012-12-31 15:25 UTC (permalink / raw)
  To: andim2; +Cc: Roger Luethi, netdev, Francois Romieu

From: Andreas Mohr <andim2@users.sf.net>

This patchset fixes suspend/resume of via-rhine in the NetworkManager case
(patch 0001), with subsequent patches being predominantly
about general cleanup/renovation work
(one patch adds get_regs() ethtool support, though).

Currently marked as RFC since it's somewhat larger,
without prior review activity.

checkpatch.pl'd patchset against a slightly oldish master
(current state of via-rhine.c in linux-next is identical).

Note that some parts in this patchset have a dependency on predecessors
(e.g. __read_mostly comes to mind).

I managed to stay at 15 patches, thus right at (below) the
official mailing list patch limit.

Somehow Christmas must have been mighty boring :)

And one of the patches narrows down on non-default
compiler warning levels, too (c.f. my recent LKML tirade).

The first patch (resume fix) possibly is -stable material,
but since layer separation currently is not crystal clear
there might be some risk, thus I'm hesitating.

Thanks!


Andreas Mohr (15):
  via-rhine: YARB: fix broken resume of ifdown case (NetworkManager).
  via-rhine: some suspend/resume cleanup.
  via-rhine: small rhine_wait_bit() improvement.
  via-rhine: handle compile warnings (use PCI_VDEVICE macro).
  via-rhine: Spelling/phrases cleanup.
  via-rhine: The Great Renaming.
  via-rhine: MMIO: move register verify into helper function.
  via-rhine: MMIO: move support decision (compile-time-only to
    runtime).
  via-rhine: mark some variables as __read_mostly.
  via-rhine: WOL: remove duplication into a helper.
  via-rhine: WOL: separate WOL configuration (and its logging).
  via-rhine: implement get_regs() ethtool ops.
  via-rhine: misc. cleanup.
  via-rhine: The Great Deduplication.
  via-rhine: add helper (reduce type-unsafe void * assignments).

 drivers/net/ethernet/via/via-rhine.c |  572 +++++++++++++++++++++++-----------
 1 files changed, 396 insertions(+), 176 deletions(-)

-- 
1.7.2.5

^ permalink raw reply

* [PATCH RFC 12/15] via-rhine: implement get_regs() ethtool ops.
From: Andreas Mohr @ 2012-12-31 15:25 UTC (permalink / raw)
  To: andim2; +Cc: Roger Luethi, netdev, Francois Romieu
In-Reply-To: <1356967549-5056-1-git-send-email-andi@lisas.de>

From: Andreas Mohr <andim2@users.sf.net>

Quite useful to pinpoint pre-suspend vs. post-resume register mismatches.
Adds io_size member for use in rhine_ethop_get_regs_len().

Signed-off-by: Andreas Mohr <andim2@users.sf.net>
---
 drivers/net/ethernet/via/via-rhine.c |   40 ++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 8950eb0..90d109a 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -452,6 +452,7 @@ struct rhine_private {
 	struct work_struct reset_task;
 
 	u32 msg_enable;
+	int io_size;
 
 	/* Frequently used values: keep some adjacent for cache effect. */
 	u32 quirks;
@@ -1001,6 +1002,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	rp = netdev_priv(dev);
 	rp->dev = dev;
+	rp->io_size = io_size;
 	rp->quirks = quirks;
 	rp->pioaddr = pioaddr;
 	rp->pdev = pdev;
@@ -2199,6 +2201,42 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value)
 	rp->msg_enable = value;
 }
 
+/*
+ * ethtool get_regs() handlers.
+ * Use e.g. to pinpoint pre-suspend vs. post-resume register mismatches
+ * due to yet another all-too-frequent suspend/resume issue.
+ */
+static int
+rhine_ethop_get_regs_len(struct net_device *dev)
+{
+	struct rhine_private *rp = netdev_priv(dev);
+	return rp->io_size;
+}
+
+static void
+rhine_ethop_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+	struct rhine_private *rp = netdev_priv(dev);
+	unsigned long flags;
+	void __iomem *ioaddr = rp->base;
+	u8 *p8 = (u8 *)p;
+	int len = regs->len;
+	int len_max = rhine_ethop_get_regs_len(dev);
+	int i = 0;
+
+	if (len > len_max)
+		len = len_max;
+
+	regs->version = 1;
+
+	memset(p, 0xFF, len);
+
+	spin_lock_irqsave(&rp->lock, flags);
+	for (i = 0; i < len; ++i)
+		p8[i] = ioread8(ioaddr + i);
+	spin_unlock_irqrestore(&rp->lock, flags);
+}
+
 /* Indicates the set of WOL features supported by this card rev. */
 static inline u32
 rhine_wol_support_bits_get(struct rhine_private *rp)
@@ -2241,6 +2279,8 @@ rhine_ethop_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
 static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_drvinfo		= netdev_get_drvinfo,
+	.get_regs_len		= rhine_ethop_get_regs_len,
+	.get_regs		= rhine_ethop_get_regs,
 	.get_settings		= netdev_get_settings,
 	.set_settings		= netdev_set_settings,
 	.nway_reset		= netdev_nway_reset,
-- 
1.7.2.5

^ permalink raw reply related


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