Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7394d24 authored by Cong Wang's avatar Cong Wang Committed by David S. Miller
Browse files

netpoll: prepare for ipv6



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

Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: default avatarCong Wang <amwang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0c7768a0
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -269,11 +269,13 @@ 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)
		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)
		return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
}

@@ -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);
}
+11 −2
Original line number Diff line number Diff line
@@ -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;
	union inet_addr local_ip, remote_ip;
	bool ipv6;
	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;
+224 −178
Original line number Diff line number Diff line
@@ -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);
	}
}

@@ -216,14 +216,14 @@ static void netpoll_poll_dev(struct net_device *dev)

			bond_dev = netdev_master_upper_dev_get_rcu(dev);
			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();
}
@@ -386,7 +386,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
	static atomic_t ip_ident;

	udp_len = len + sizeof(*udph);
	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,
@@ -403,9 +405,11 @@ 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);

	if (!np->ipv6) {
		udph->check = 0;
	udph->check = csum_tcpudp_magic(np->local_ip,
					np->remote_ip,
		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)
@@ -424,13 +428,15 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
		iph->ttl      = 64;
		iph->protocol = IPPROTO_UDP;
		iph->check    = 0;
	put_unaligned(np->local_ip, &(iph->saddr));
	put_unaligned(np->remote_ip, &(iph->daddr));
		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);

@@ -440,7 +446,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;
@@ -451,7 +457,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;
@@ -469,6 +475,8 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
	if (!hits)
		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;
@@ -505,7 +513,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)

		spin_lock_irqsave(&npinfo->rx_lock, flags);
		list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
		if (tip != np->local_ip)
			if (tip != np->local_ip.ip)
				continue;

			hlen = LL_RESERVED_SPACE(np->dev);
@@ -558,6 +566,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
		}
		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
	}
}

int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
{
@@ -576,7 +585,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;
	}

@@ -587,13 +596,14 @@ 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 (proto == ETH_P_IP) {
		if (!pskb_may_pull(skb, sizeof(struct iphdr)))
			goto out;
		iph = (struct iphdr *)skb->data;
@@ -628,11 +638,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
			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 && np->local_ip != iph->daddr)
			if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
				continue;
		if (np->remote_ip && np->remote_ip != iph->saddr)
			if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
				continue;
			if (np->local_port && np->local_port != ntohs(uh->dest))
				continue;
@@ -642,6 +651,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
				       ulen - sizeof(struct udphdr));
			hits++;
		}
	}

	if (!hits)
		goto out;
@@ -661,17 +671,40 @@ 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 IS_ENABLED(CONFIG_IPV6)
		if (!*end)
			return 1;
#else
		return -1;
#endif
	}
	return -1;
}

int netpoll_parse_options(struct netpoll *np, char *opt)
{
	char *cur=opt, *delim;
	int ipv6;

	if (*cur != '@') {
		if ((delim = strchr(cur, '@')) == NULL)
@@ -687,7 +720,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 = (bool)ipv6;
		cur = delim;
	}
	cur++;
@@ -719,7 +756,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 != (bool)ipv6)
		goto parse_failed;
	else
		np->ipv6 = (bool)ipv6;
	cur = delim + 1;

	if (*cur != 0) {
@@ -767,7 +810,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);

@@ -859,10 +902,12 @@ int netpoll_setup(struct netpoll *np)
		}
	}

	if (!np->local_ip) {
	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) {
				rcu_read_unlock();
				np_err(np, "no IP address for %s, aborting\n",
@@ -871,9 +916,10 @@ int netpoll_setup(struct netpoll *np)
				goto put;
			}

		np->local_ip = in_dev->ifa_list->ifa_local;
			np->local_ip.ip = in_dev->ifa_list->ifa_local;
			rcu_read_unlock();
		np_info(np, "local IP %pI4\n", &np->local_ip);
			np_info(np, "local IP %pI4\n", &np->local_ip.ip);
		}
	}

	/* fill up the skb queue */
@@ -906,7 +952,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 */