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

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
...@@ -269,11 +269,13 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) ...@@ -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) 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); return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
} }
static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) 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); 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, ...@@ -410,7 +412,8 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
return -EINVAL; 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); return strnlen(buf, count);
} }
...@@ -426,7 +429,8 @@ static ssize_t store_remote_ip(struct netconsole_target *nt, ...@@ -426,7 +429,8 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
return -EINVAL; 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); return strnlen(buf, count);
} }
......
...@@ -12,13 +12,22 @@ ...@@ -12,13 +12,22 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/list.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 netpoll {
struct net_device *dev; struct net_device *dev;
char dev_name[IFNAMSIZ]; char dev_name[IFNAMSIZ];
const char *name; const char *name;
void (*rx_hook)(struct netpoll *, int, char *, int); 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; u16 local_port, remote_port;
u8 remote_mac[ETH_ALEN]; u8 remote_mac[ETH_ALEN];
...@@ -33,7 +42,7 @@ struct netpoll_info { ...@@ -33,7 +42,7 @@ struct netpoll_info {
spinlock_t rx_lock; spinlock_t rx_lock;
struct list_head rx_np; /* netpolls that registered an rx_hook */ 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 sk_buff_head txq;
struct delayed_work tx_work; struct delayed_work tx_work;
......
...@@ -55,7 +55,7 @@ static atomic_t trapped; ...@@ -55,7 +55,7 @@ static atomic_t trapped;
MAX_UDP_CHUNK) MAX_UDP_CHUNK)
static void zap_completion_queue(void); 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; static unsigned int carrier_timeout = 4;
module_param(carrier_timeout, uint, 0644); module_param(carrier_timeout, uint, 0644);
...@@ -181,13 +181,13 @@ static void poll_napi(struct net_device *dev) ...@@ -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) { if (npi) {
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue(&npi->arp_tx))) while ((skb = skb_dequeue(&npi->neigh_tx)))
netpoll_arp_reply(skb, npi); netpoll_neigh_reply(skb, npi);
} }
} }
...@@ -216,14 +216,14 @@ static void netpoll_poll_dev(struct net_device *dev) ...@@ -216,14 +216,14 @@ static void netpoll_poll_dev(struct net_device *dev)
bond_dev = netdev_master_upper_dev_get_rcu(dev); bond_dev = netdev_master_upper_dev_get_rcu(dev);
bond_ni = rcu_dereference_bh(bond_dev->npinfo); 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->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(); zap_completion_queue();
} }
...@@ -386,7 +386,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) ...@@ -386,7 +386,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
static atomic_t ip_ident; static atomic_t ip_ident;
udp_len = len + sizeof(*udph); udp_len = len + sizeof(*udph);
if (!np->ipv6)
ip_len = udp_len + sizeof(*iph); ip_len = udp_len + sizeof(*iph);
total_len = ip_len + LL_RESERVED_SPACE(np->dev); total_len = ip_len + LL_RESERVED_SPACE(np->dev);
skb = find_skb(np, total_len + np->dev->needed_tailroom, 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) ...@@ -403,9 +405,11 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
udph->source = htons(np->local_port); udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port); udph->dest = htons(np->remote_port);
udph->len = htons(udp_len); udph->len = htons(udp_len);
if (!np->ipv6) {
udph->check = 0; udph->check = 0;
udph->check = csum_tcpudp_magic(np->local_ip, udph->check = csum_tcpudp_magic(np->local_ip.ip,
np->remote_ip, np->remote_ip.ip,
udp_len, IPPROTO_UDP, udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0)); csum_partial(udph, udp_len, 0));
if (udph->check == 0) if (udph->check == 0)
...@@ -424,13 +428,15 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) ...@@ -424,13 +428,15 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
iph->ttl = 64; iph->ttl = 64;
iph->protocol = IPPROTO_UDP; iph->protocol = IPPROTO_UDP;
iph->check = 0; iph->check = 0;
put_unaligned(np->local_ip, &(iph->saddr)); put_unaligned(np->local_ip.ip, &(iph->saddr));
put_unaligned(np->remote_ip, &(iph->daddr)); put_unaligned(np->remote_ip.ip, &(iph->daddr));
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP); skb->protocol = eth->h_proto = htons(ETH_P_IP);
}
memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN); memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, np->remote_mac, 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) ...@@ -440,7 +446,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
} }
EXPORT_SYMBOL(netpoll_send_udp); 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; struct arphdr *arp;
unsigned char *arp_ptr; unsigned char *arp_ptr;
...@@ -451,7 +457,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -451,7 +457,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
struct netpoll *np, *tmp; struct netpoll *np, *tmp;
unsigned long flags; unsigned long flags;
int hlen, tlen; int hlen, tlen;
int hits = 0; int hits = 0, proto;
if (list_empty(&npinfo->rx_np)) if (list_empty(&npinfo->rx_np))
return; return;
...@@ -469,6 +475,8 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -469,6 +475,8 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
if (!hits) if (!hits)
return; return;
proto = ntohs(eth_hdr(skb)->h_proto);
if (proto == ETH_P_IP) {
/* No arp on this interface */ /* No arp on this interface */
if (skb->dev->flags & IFF_NOARP) if (skb->dev->flags & IFF_NOARP)
return; return;
...@@ -505,7 +513,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -505,7 +513,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
spin_lock_irqsave(&npinfo->rx_lock, flags); spin_lock_irqsave(&npinfo->rx_lock, flags);
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
if (tip != np->local_ip) if (tip != np->local_ip.ip)
continue; continue;
hlen = LL_RESERVED_SPACE(np->dev); hlen = LL_RESERVED_SPACE(np->dev);
...@@ -557,6 +565,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -557,6 +565,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
break; 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) 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) ...@@ -576,7 +585,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
/* check if netpoll clients need ARP */ /* check if netpoll clients need ARP */
if (skb->protocol == htons(ETH_P_ARP) && if (skb->protocol == htons(ETH_P_ARP) &&
atomic_read(&trapped)) { atomic_read(&trapped)) {
skb_queue_tail(&npinfo->arp_tx, skb); skb_queue_tail(&npinfo->neigh_tx, skb);
return 1; return 1;
} }
...@@ -587,13 +596,14 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -587,13 +596,14 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
} }
proto = ntohs(eth_hdr(skb)->h_proto); proto = ntohs(eth_hdr(skb)->h_proto);
if (proto != ETH_P_IP) if (proto != ETH_P_IP && proto != ETH_P_IPV6)
goto out; goto out;
if (skb->pkt_type == PACKET_OTHERHOST) if (skb->pkt_type == PACKET_OTHERHOST)
goto out; goto out;
if (skb_shared(skb)) if (skb_shared(skb))
goto out; goto out;
if (proto == ETH_P_IP) {
if (!pskb_may_pull(skb, sizeof(struct iphdr))) if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out; goto out;
iph = (struct iphdr *)skb->data; iph = (struct iphdr *)skb->data;
...@@ -628,11 +638,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -628,11 +638,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
goto out; goto out;
if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
goto out; goto out;
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { 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; continue;
if (np->remote_ip && np->remote_ip != iph->saddr) if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
continue; continue;
if (np->local_port && np->local_port != ntohs(uh->dest)) if (np->local_port && np->local_port != ntohs(uh->dest))
continue; continue;
...@@ -642,6 +651,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -642,6 +651,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
ulen - sizeof(struct udphdr)); ulen - sizeof(struct udphdr));
hits++; hits++;
} }
}
if (!hits) if (!hits)
goto out; goto out;
...@@ -661,17 +671,40 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) ...@@ -661,17 +671,40 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
void netpoll_print_options(struct netpoll *np) void netpoll_print_options(struct netpoll *np)
{ {
np_info(np, "local port %d\n", np->local_port); 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, "interface '%s'\n", np->dev_name);
np_info(np, "remote port %d\n", np->remote_port); 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); np_info(np, "remote ethernet address %pM\n", np->remote_mac);
} }
EXPORT_SYMBOL(netpoll_print_options); 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) int netpoll_parse_options(struct netpoll *np, char *opt)
{ {
char *cur=opt, *delim; char *cur=opt, *delim;
int ipv6;
if (*cur != '@') { if (*cur != '@') {
if ((delim = strchr(cur, '@')) == NULL) if ((delim = strchr(cur, '@')) == NULL)
...@@ -687,7 +720,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt) ...@@ -687,7 +720,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
if ((delim = strchr(cur, '/')) == NULL) if ((delim = strchr(cur, '/')) == NULL)
goto parse_failed; goto parse_failed;
*delim = 0; *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 = delim;
} }
cur++; cur++;
...@@ -719,7 +756,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt) ...@@ -719,7 +756,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
if ((delim = strchr(cur, '/')) == NULL) if ((delim = strchr(cur, '/')) == NULL)
goto parse_failed; goto parse_failed;
*delim = 0; *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; cur = delim + 1;
if (*cur != 0) { if (*cur != 0) {
...@@ -767,7 +810,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) ...@@ -767,7 +810,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
INIT_LIST_HEAD(&npinfo->rx_np); INIT_LIST_HEAD(&npinfo->rx_np);
spin_lock_init(&npinfo->rx_lock); 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); skb_queue_head_init(&npinfo->txq);
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
...@@ -859,10 +902,12 @@ int netpoll_setup(struct netpoll *np) ...@@ -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(); rcu_read_lock();
in_dev = __in_dev_get_rcu(ndev); in_dev = __in_dev_get_rcu(ndev);
if (!in_dev || !in_dev->ifa_list) { if (!in_dev || !in_dev->ifa_list) {
rcu_read_unlock(); rcu_read_unlock();
np_err(np, "no IP address for %s, aborting\n", np_err(np, "no IP address for %s, aborting\n",
...@@ -871,9 +916,10 @@ int netpoll_setup(struct netpoll *np) ...@@ -871,9 +916,10 @@ int netpoll_setup(struct netpoll *np)
goto put; goto put;
} }
np->local_ip = in_dev->ifa_list->ifa_local; np->local_ip.ip = in_dev->ifa_list->ifa_local;
rcu_read_unlock(); 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 */ /* fill up the skb queue */
...@@ -906,7 +952,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) ...@@ -906,7 +952,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
struct netpoll_info *npinfo = struct netpoll_info *npinfo =
container_of(rcu_head, struct netpoll_info, rcu); 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); skb_queue_purge(&npinfo->txq);
/* we can't call cancel_delayed_work_sync here, as we are in softirq */ /* we can't call cancel_delayed_work_sync here, as we are in softirq */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment