X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fcore%2Fnetpoll.c;h=0860e0827134682af7e7b5799cc26c8a313e3ac2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=2f0115eef7ca685325c3b3b130f04dd467523ad8;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 2f0115eef..0860e0827 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include /* * We maintain a small pool of fully-sized skbs, to make sure the @@ -29,14 +31,18 @@ #define MAX_SKBS 32 #define MAX_UDP_CHUNK 1460 -static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(skb_list_lock); static int nr_skbs; static struct sk_buff *skbs; -static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(rx_list_lock); static LIST_HEAD(rx_list); -static int trapped; +static atomic_t trapped; +static DEFINE_SPINLOCK(netpoll_poll_lock); + +#define NETPOLL_RX_ENABLED 1 +#define NETPOLL_RX_DROP 2 #define MAX_SKB_SIZE \ (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ @@ -59,20 +65,46 @@ static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); } -void netpoll_poll(struct netpoll *np) +/* + * Check whether delayed processing was scheduled for our current CPU, + * and then manually invoke NAPI polling to pump data off the card. + * + * In cases where there is bi-directional communications, reading only + * one message at a time can lead to packets being dropped by the + * network adapter, forcing superfluous retries and possibly timeouts. + * Thus, we set our budget to greater than 1. + */ +static void poll_napi(struct netpoll *np) { - int budget = 1; + int budget = 16; + unsigned long flags; + struct softnet_data *queue; + + spin_lock_irqsave(&netpoll_poll_lock, flags); + queue = &__get_cpu_var(softnet_data); + if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) && + !list_empty(&queue->poll_list)) { + np->dev->netpoll_rx |= NETPOLL_RX_DROP; + atomic_inc(&trapped); + np->dev->poll(np->dev, &budget); + + atomic_dec(&trapped); + np->dev->netpoll_rx &= ~NETPOLL_RX_DROP; + } + spin_unlock_irqrestore(&netpoll_poll_lock, flags); +} + +void netpoll_poll(struct netpoll *np) +{ if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) return; /* Process pending work on NIC */ np->dev->poll_controller(np->dev); + if (np->dev->poll) + poll_napi(np); - /* If scheduling is stopped, tickle NAPI bits */ - if(trapped && np->dev->poll && - test_bit(__LINK_STATE_RX_SCHED, &np->dev->state)) - np->dev->poll(np->dev, &budget); zap_completion_queue(); } @@ -155,7 +187,7 @@ repeat: return skb; } -void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) +static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { int status; @@ -168,6 +200,18 @@ repeat: spin_lock(&np->dev->xmit_lock); np->dev->xmit_lock_owner = smp_processor_id(); + /* + * network drivers do not expect to be called if the queue is + * stopped. + */ + if (netif_queue_stopped(np->dev)) { + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + netpoll_poll(np); + goto repeat; + } + status = np->dev->hard_start_xmit(skb, np->dev); np->dev->xmit_lock_owner = -1; spin_unlock(&np->dev->xmit_lock); @@ -206,17 +250,17 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); - iph->version = 4; - iph->ihl = 5; + /* iph->version = 4; iph->ihl = 5; */ + put_unaligned(0x45, (unsigned char *)iph); iph->tos = 0; - iph->tot_len = htons(ip_len); + put_unaligned(htons(ip_len), &(iph->tot_len)); iph->id = 0; iph->frag_off = 0; iph->ttl = 64; iph->protocol = IPPROTO_UDP; iph->check = 0; - iph->saddr = htonl(np->local_ip); - iph->daddr = htonl(np->remote_ip); + put_unaligned(htonl(np->local_ip), &(iph->saddr)); + put_unaligned(htonl(np->remote_ip), &(iph->daddr)); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); @@ -237,14 +281,14 @@ static void arp_reply(struct sk_buff *skb) struct sk_buff *send_skb; unsigned long flags; struct list_head *p; - struct netpoll *np = 0; + struct netpoll *np = NULL; spin_lock_irqsave(&rx_list_lock, flags); list_for_each(p, &rx_list) { np = list_entry(p, struct netpoll, rx_list); if ( np->dev == skb->dev ) break; - np = 0; + np = NULL; } spin_unlock_irqrestore(&rx_list_lock, flags); @@ -337,12 +381,13 @@ int netpoll_rx(struct sk_buff *skb) goto out; /* check if netpoll clients need ARP */ - if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) { + if (skb->protocol == __constant_htons(ETH_P_ARP) && + atomic_read(&trapped)) { arp_reply(skb); return 1; } - proto = ntohs(skb->mac.ethernet->h_proto); + proto = ntohs(eth_hdr(skb)->h_proto); if (proto != ETH_P_IP) goto out; if (skb->pkt_type == PACKET_OTHERHOST) @@ -400,7 +445,7 @@ int netpoll_rx(struct sk_buff *skb) spin_unlock_irqrestore(&rx_list_lock, flags); out: - return trapped; + return atomic_read(&trapped); } int netpoll_parse_options(struct netpoll *np, char *opt) @@ -411,7 +456,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if ((delim = strchr(cur, '@')) == NULL) goto parse_failed; *delim=0; - np->local_port=simple_strtol(cur, 0, 10); + np->local_port=simple_strtol(cur, NULL, 10); cur=delim; } cur++; @@ -446,7 +491,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if ((delim = strchr(cur, '@')) == NULL) goto parse_failed; *delim=0; - np->remote_port=simple_strtol(cur, 0, 10); + np->remote_port=simple_strtol(cur, NULL, 10); cur=delim; } cur++; @@ -468,29 +513,29 @@ int netpoll_parse_options(struct netpoll *np, char *opt) if ((delim = strchr(cur, ':')) == NULL) goto parse_failed; *delim=0; - np->remote_mac[0]=simple_strtol(cur, 0, 16); + np->remote_mac[0]=simple_strtol(cur, NULL, 16); cur=delim+1; if ((delim = strchr(cur, ':')) == NULL) goto parse_failed; *delim=0; - np->remote_mac[1]=simple_strtol(cur, 0, 16); + np->remote_mac[1]=simple_strtol(cur, NULL, 16); cur=delim+1; if ((delim = strchr(cur, ':')) == NULL) goto parse_failed; *delim=0; - np->remote_mac[2]=simple_strtol(cur, 0, 16); + np->remote_mac[2]=simple_strtol(cur, NULL, 16); cur=delim+1; if ((delim = strchr(cur, ':')) == NULL) goto parse_failed; *delim=0; - np->remote_mac[3]=simple_strtol(cur, 0, 16); + np->remote_mac[3]=simple_strtol(cur, NULL, 16); cur=delim+1; if ((delim = strchr(cur, ':')) == NULL) goto parse_failed; *delim=0; - np->remote_mac[4]=simple_strtol(cur, 0, 16); + np->remote_mac[4]=simple_strtol(cur, NULL, 16); cur=delim+1; - np->remote_mac[5]=simple_strtol(cur, 0, 16); + np->remote_mac[5]=simple_strtol(cur, NULL, 16); } printk(KERN_INFO "%s: remote ethernet address " @@ -529,7 +574,7 @@ int netpoll_setup(struct netpoll *np) goto release; } - if (!(ndev->flags & IFF_UP)) { + if (!netif_running(ndev)) { unsigned short oflags; unsigned long atmost, atleast; @@ -572,16 +617,18 @@ int netpoll_setup(struct netpoll *np) memcpy(np->local_mac, ndev->dev_addr, 6); if (!np->local_ip) { - in_dev = in_dev_get(ndev); + rcu_read_lock(); + in_dev = __in_dev_get(ndev); - if (!in_dev) { + if (!in_dev || !in_dev->ifa_list) { + rcu_read_unlock(); printk(KERN_ERR "%s: no IP address for %s, aborting\n", np->name, np->dev_name); goto release; } np->local_ip = ntohl(in_dev->ifa_list->ifa_local); - in_dev_put(in_dev); + rcu_read_unlock(); printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", np->name, HIPQUAD(np->local_ip)); } @@ -591,9 +638,7 @@ int netpoll_setup(struct netpoll *np) if(np->rx_hook) { unsigned long flags; -#ifdef CONFIG_NETPOLL_RX - np->dev->netpoll_rx = 1; -#endif + np->dev->netpoll_rx = NETPOLL_RX_ENABLED; spin_lock_irqsave(&rx_list_lock, flags); list_add(&np->rx_list, &rx_list); @@ -608,29 +653,31 @@ int netpoll_setup(struct netpoll *np) void netpoll_cleanup(struct netpoll *np) { - if(np->rx_hook) { + if (np->rx_hook) { unsigned long flags; spin_lock_irqsave(&rx_list_lock, flags); list_del(&np->rx_list); -#ifdef CONFIG_NETPOLL_RX - np->dev->netpoll_rx = 0; -#endif spin_unlock_irqrestore(&rx_list_lock, flags); } + if (np->dev) + np->dev->netpoll_rx = 0; dev_put(np->dev); - np->dev = 0; + np->dev = NULL; } -int netpoll_trap() +int netpoll_trap(void) { - return trapped; + return atomic_read(&trapped); } void netpoll_set_trap(int trap) { - trapped = trap; + if (trap) + atomic_inc(&trapped); + else + atomic_dec(&trapped); } EXPORT_SYMBOL(netpoll_set_trap); @@ -638,6 +685,5 @@ EXPORT_SYMBOL(netpoll_trap); EXPORT_SYMBOL(netpoll_parse_options); EXPORT_SYMBOL(netpoll_setup); EXPORT_SYMBOL(netpoll_cleanup); -EXPORT_SYMBOL(netpoll_send_skb); EXPORT_SYMBOL(netpoll_send_udp); EXPORT_SYMBOL(netpoll_poll);