diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-06-28 15:03:12 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-06-28 15:03:12 +0400 |
commit | 734e96455c4da83a5011c53772ed5136f592c9a1 (patch) | |
tree | e724b6e9d6e73456d3a3fc32d00c464fbec5bfa1 /drivers/ipoe | |
parent | 288f9babe7cca463856de11ae70067105ca70805 (diff) | |
download | accel-ppp-734e96455c4da83a5011c53772ed5136f592c9a1.tar.gz accel-ppp-734e96455c4da83a5011c53772ed5136f592c9a1.zip |
ipoe: interface statistics
Diffstat (limited to 'drivers/ipoe')
-rw-r--r-- | drivers/ipoe/CMakeLists.txt | 2 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 545 |
2 files changed, 367 insertions, 180 deletions
diff --git a/drivers/ipoe/CMakeLists.txt b/drivers/ipoe/CMakeLists.txt index fb5a51e4..14ac12eb 100644 --- a/drivers/ipoe/CMakeLists.txt +++ b/drivers/ipoe/CMakeLists.txt @@ -10,7 +10,7 @@ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/driver/ipoe.ko DEPENDS ipoe.c ipoe.h ) -ADD_CUSTOM_TARGET(isg_drv ALL +ADD_CUSTOM_TARGET(ipoe_drv ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/driver/ipoe.ko ) diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index 6749fa8b..612b0cbd 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -16,29 +16,39 @@ #include <linux/semaphore.h> #include <linux/rbtree.h> #include <linux/version.h> -#include <net/genetlink.h> +#include <net/genetlink.h> +#include <net/route.h> #include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> +#include <net/flow.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include "ipoe.h" -#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) -#define HASH_SIZE 16 - -#define NEED_UPDATE 1 +#define BEGIN_UPDATE 1 #define UPDATE 2 +#define END_UPDATE 3 + +#define IPOE_MAGIC 0x55aa #ifndef DEFINE_SEMAPHORE #define DEFINE_SEMAPHORE(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) #endif -struct ipoe_session -{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +struct ipoe_stats { + struct u64_stats_sync sync; + u64 packets; + u64 bytes; +}; +#endif + +struct ipoe_session { struct rb_node node; + struct list_head entry; __be32 addr; __be32 peer_addr; @@ -47,31 +57,24 @@ struct ipoe_session struct net_device *dev; struct net_device *link_dev; - /*struct tasklet_struct tasklet; - int tasklet_pending; - - struct u64_status_sync rsync; - u64 rx_packets; - u64 rx_bytes; - struct sk_buff_head rq; - - struct u64_status_sync tsync; - u64 tx_packets; - u64 tx_bytes; - struct sk_buff_head tq;*/ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + struct ipoe_stats __percpu *rx_stats; + struct ipoe_stats __percpu *tx_stats; +#endif + int l3:1; int drop:1; }; -struct rb_root ipoe_rbt = RB_ROOT; -static atomic_t ipoe_rlock; -static atomic_t ipoe_update; +static struct rb_root ipoe_rbt = RB_ROOT; +static LIST_HEAD(ipoe_list); +static int ipoe_rcv_active; +static int ipoe_update; static DEFINE_SEMAPHORE(ipoe_wlock); - -struct sk_buff_head ipoe_rq; -struct tasklet_struct ipoe_rq_tasklet; +static DEFINE_SPINLOCK(ipoe_lock); static struct ipoe_session *ipoe_lookup(__be32 addr, struct rb_node **r_parent, struct rb_node ***r_p); +static struct ipoe_session *ipoe_lookup_list(__be32 addr); static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) @@ -80,54 +83,15 @@ static const struct net_device_ops ipoe_netdev_ops; static struct genl_family ipoe_nl_family; -static void ipoe_recv_rq(unsigned long arg) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +static void ipoe_update_stats(struct sk_buff *skb, struct ipoe_stats *st) { - struct sk_buff *skb; - int upd; - struct iphdr *iph; - int noff; - struct ipoe_session *ses; - - atomic_inc(&ipoe_rlock); - if (atomic_read(&ipoe_update) == UPDATE) { - atomic_dec(&ipoe_rlock); - tasklet_schedule(&ipoe_rq_tasklet); - return; - } - - while ((skb = skb_dequeue(&ipoe_rq))) { - noff = skb_network_offset(skb); - - iph = ip_hdr(skb); - - ses = ipoe_lookup(iph->saddr, NULL, NULL); - if (!ses) - goto drop; - - if (ses->drop) - goto drop; - - if (ses->addr && ipoe_do_nat(skb, ses->addr, 0)) - goto drop; - - skb->dev = ses->dev; - //skb->skb_iif = ses->link_dev->ifindex; - - netif_rx(skb); - - if (atomic_read(&ipoe_update) == NEED_UPDATE) - break; - - continue; - - drop: - kfree_skb(skb); - } - - upd = atomic_read(&ipoe_update); - if (atomic_dec_and_test(&ipoe_rlock) && upd == NEED_UPDATE) - atomic_set(&ipoe_update, UPDATE); + u64_stats_update_begin(&st->sync); + st->packets++; + st->bytes += skb->len; + u64_stats_update_end(&st->sync); } +#endif static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) { @@ -238,6 +202,60 @@ static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) return 0; } +static struct net *pick_net(struct sk_buff *skb) +{ +#ifdef CONFIG_NET_NS + const struct dst_entry *dst; + + if (skb->dev != NULL) + return dev_net(skb->dev); + dst = skb_dst(skb); + if (dst != NULL && dst->dev != NULL) + return dev_net(dst->dev); +#endif + return &init_net; +} + +static int ipoe_route4(struct sk_buff *skb) +{ + const struct iphdr *iph = ip_hdr(skb); + struct net *net = pick_net(skb); + struct rtable *rt; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + struct flowi fl4; +#else + struct flowi4 fl4; +#endif + + memset(&fl4, 0, sizeof(fl4)); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + fl4.fl4_dst = iph->daddr; + fl4.fl4_tos = RT_TOS(iph->tos); + fl4.fl4_scope = RT_SCOPE_UNIVERSE; + if (ip_route_output_key(net, &rt, &fl4)) + return -1; +#else + fl4.daddr = iph->daddr; + fl4.flowi4_tos = RT_TOS(iph->tos); + fl4.flowi4_scope = RT_SCOPE_UNIVERSE; + rt = ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) + return -1; +#endif + + skb_dst_drop(skb); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + skb_dst_set(skb, &rt->u.dst); + skb->dev = rt->u.dst.dev; +#else + skb_dst_set(skb, &rt->dst); + skb->dev = rt->dst.dev; +#endif + + return 0; +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) static int ipoe_xmit(struct sk_buff *skb, struct net_device *dev) #else @@ -263,19 +281,37 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) //pr_info("ipoe: xmit %08x %08x\n", iph->saddr, iph->daddr); - /*u64_stats_update_begin(&ses->tsync); - ses->tx_packets++; - ses->tx_bytes += skb->len; - u64_stats_update_end(&ses->tsync);*/ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + ipoe_update_stats(skb, this_cpu_ptr(ses->tx_stats)); +#else + stats->tx_packets++; + stats->tx_bytes += skb->len; +#endif if (iph->daddr == ses->addr) { if (ipoe_do_nat(skb, ses->peer_addr, 1)) goto drop; - eth = (struct ethhdr *)skb->data; + if (ses->l3) { + iph = ip_hdr(skb); + + ip_send_check(iph); + + if (ipoe_route4(skb)) + goto drop; + + pskb_pull(skb, ETH_HLEN); + skb_reset_network_header(skb); + + ip_local_out(skb); + + return NETDEV_TX_OK; + } else { + eth = (struct ethhdr *)skb->data; - memcpy(eth->h_dest, ses->hwaddr, ETH_ALEN); - memcpy(eth->h_source, ses->link_dev->dev_addr, ETH_ALEN); + memcpy(eth->h_dest, ses->hwaddr, ETH_ALEN); + memcpy(eth->h_source, ses->link_dev->dev_addr, ETH_ALEN); + } } } /*else if (skb->protocol == htons(ETH_P_ARP)) { if (!pskb_may_pull(skb, arp_hdr_len(dev) + noff)) @@ -300,7 +336,7 @@ static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) }*/ skb->dev = ses->link_dev; - skb->skb_iif = dev->ifindex; + //skb->skb_iif = dev->ifindex; dev_queue_xmit(skb); return NETDEV_TX_OK; @@ -310,6 +346,25 @@ drop: return NETDEV_TX_OK; } +static inline void ipoe_rcv_lock(void) +{ + spin_lock(&ipoe_lock); + ++ipoe_rcv_active; + spin_unlock(&ipoe_lock); +} + +static inline void ipoe_rcv_unlock(void) +{ + spin_lock(&ipoe_lock); + if (--ipoe_rcv_active == 0) { + if (ipoe_update == BEGIN_UPDATE) + ipoe_update = UPDATE; + else if (ipoe_update == END_UPDATE) + ipoe_update = 0; + } + spin_unlock(&ipoe_lock); +} + static int ipoe_rcv_arp(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct ipoe_session *ses = NULL; @@ -317,14 +372,20 @@ static int ipoe_rcv_arp(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; int noff; __be32 sip; - int upd; struct sk_buff *skb1; + unsigned char *cb_ptr; + struct net_device_stats *stats; //pr_info("ipoe: recv arp\n"); if (skb->pkt_type == PACKET_OTHERHOST) goto drop; + cb_ptr = skb->cb + sizeof(skb->cb) - 2; + + if (*(__u16 *)cb_ptr == IPOE_MAGIC) + goto drop; + noff = skb_network_offset(skb); if (!pskb_may_pull(skb, arp_hdr_len(dev) + noff)) @@ -340,46 +401,53 @@ static int ipoe_rcv_arp(struct sk_buff *skb, struct net_device *dev, struct pack //pr_info("ipoe: recv arp %08x\n", sip); - atomic_inc(&ipoe_rlock); - upd = atomic_read(&ipoe_update); - if (upd) - goto drop_unlock; + ipoe_rcv_lock(); + + if (ipoe_update == UPDATE) + ses = ipoe_lookup_list(sip); + else + ses = ipoe_lookup(sip, NULL, NULL); - ses = ipoe_lookup(sip, NULL, NULL); if (!ses) goto drop_unlock; - if (ses->drop || ses->addr) + stats = &ses->dev->stats; + + if (ses->drop) goto drop_unlock; - if (skb->dev == ses->dev) + if (ses->addr || skb->dev == ses->dev) { + ses = NULL; goto drop_unlock; + } - /*if (ses->addr && arp->ar_op == htons(ARPOP_REPLY)) { - if (skb_cloned(skb) && - !skb_clone_writable(skb, arp_hdr_len(dev) + noff) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto drop_unlock; - - arp = arp_hdr(skb); - arp_ptr = (unsigned char *)(arp + 1); - memcpy(arp_ptr + ETH_ALEN, &ses->addr, 4); - }*/ - skb1 = skb_clone(skb, GFP_ATOMIC); - if (!skb1) + if (!skb1) { + stats->rx_dropped++; goto drop_unlock; + } skb1->dev = ses->dev; skb1->skb_iif = ses->dev->ifindex; + cb_ptr = skb1->cb + sizeof(skb1->cb) - 2; + *(__u16 *)cb_ptr = IPOE_MAGIC; + netif_rx(skb1); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + ipoe_update_stats(skb, this_cpu_ptr(ses->rx_stats)); +#else + stats->rx_packets++; + stats->rx_bytes += skb->len; +#endif + drop_unlock: - upd = atomic_read(&ipoe_update); - if (atomic_dec_and_test(&ipoe_rlock) && upd == NEED_UPDATE) - atomic_set(&ipoe_update, UPDATE); + ipoe_rcv_unlock(); + if (ses) + skb->pkt_type = PACKET_OTHERHOST; + drop: kfree_skb(skb); return NET_RX_DROP; @@ -389,13 +457,19 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t { struct ipoe_session *ses = NULL; struct iphdr *iph; - int upd; int noff; struct sk_buff *skb1; + unsigned char *cb_ptr; + struct net_device_stats *stats; if (skb->pkt_type == PACKET_OTHERHOST) goto drop; + cb_ptr = skb->cb + sizeof(skb->cb) - 2; + + if (*(__u16 *)cb_ptr == IPOE_MAGIC) + goto drop; + noff = skb_network_offset(skb); if (!pskb_may_pull(skb, sizeof(*iph) + noff)) @@ -404,54 +478,163 @@ static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t iph = ip_hdr(skb); //pr_info("ipoe: recv %08x %08x\n", iph->saddr, iph->daddr); + + ipoe_rcv_lock(); - atomic_inc(&ipoe_rlock); - upd = atomic_read(&ipoe_update); - if (upd == NEED_UPDATE) { - skb_queue_tail(&ipoe_rq, skb); - - if (atomic_dec_and_test(&ipoe_rlock)) - atomic_set(&ipoe_update, UPDATE); - - return NET_RX_SUCCESS; - } else if (upd == UPDATE) { - skb_queue_tail(&ipoe_rq, skb); - atomic_dec(&ipoe_rlock); - return NET_RX_SUCCESS; - } - - ses = ipoe_lookup(iph->saddr, NULL, NULL); + if (ipoe_update == UPDATE) + ses = ipoe_lookup_list(iph->saddr); + else + ses = ipoe_lookup(iph->saddr, NULL, NULL); + if (!ses) goto drop_unlock; + //pr_info("ipoe: recv cb=%x\n", *(__u16 *)cb_ptr); + stats = &ses->dev->stats; + if (ses->drop) goto drop_unlock; - if (skb->dev == ses->dev) + if (skb->dev == ses->dev) { + //pr_info("ipoe: dup\n"); + ses = NULL; goto drop_unlock; + } if (ses->addr && ipoe_do_nat(skb, ses->addr, 0)) goto drop_unlock; skb1 = skb_clone(skb, GFP_ATOMIC); - if (!skb1) + if (!skb1) { + stats->rx_dropped++; goto drop_unlock; + } skb1->dev = ses->dev; skb1->skb_iif = ses->dev->ifindex; + + cb_ptr = skb1->cb + sizeof(skb1->cb) - 2; + *(__u16 *)cb_ptr = IPOE_MAGIC; netif_rx(skb1); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + ipoe_update_stats(skb, this_cpu_ptr(ses->rx_stats)); +#else + stats->rx_packets++; + stats->rx_bytes += skb->len; +#endif + drop_unlock: - upd = atomic_read(&ipoe_update); - if (atomic_dec_and_test(&ipoe_rlock) && upd == NEED_UPDATE) - atomic_set(&ipoe_update, UPDATE); + ipoe_rcv_unlock(); + + if (ses) + skb->pkt_type = PACKET_OTHERHOST; drop: kfree_skb(skb); return NET_RX_DROP; } +static struct ipoe_session *ipoe_lookup(__be32 addr, struct rb_node **r_parent, struct rb_node ***r_p) +{ + struct ipoe_session *ses; + struct rb_node **p = &ipoe_rbt.rb_node; + struct rb_node *parent = NULL; + + while (*p) { + parent = *p; + ses = rb_entry(parent, typeof(*ses), node); + if (addr < ses->peer_addr) + p = &(*p)->rb_left; + else if (addr > ses->peer_addr) + p = &(*p)->rb_right; + else + return ses; + } + + if (r_parent) { + *r_parent = parent; + *r_p = p; + } + + return NULL; +} + +static struct ipoe_session *ipoe_lookup_list(__be32 addr) +{ + struct ipoe_session *ses; + + list_for_each_entry(ses, &ipoe_list, entry) { + if (ses->peer_addr == addr) + return ses; + } + + return NULL; +} + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +static struct rtnl_link_stats64 *ipoe_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct ipoe_session *ses = netdev_priv(dev); + struct ipoe_stats *st; + unsigned int start; + int i; + u64 packets, bytes; + u64 rx_packets = 0, rx_bytes = 0, tx_packets = 0, tx_bytes = 0; + + for_each_possible_cpu(i) { + st = per_cpu_ptr(ses->rx_stats, i); + + do { + start = u64_stats_fetch_begin_bh(&st->sync); + packets = st->packets; + bytes = st->bytes; + } while (u64_stats_fetch_retry_bh(&st->sync, start)); + + rx_packets += packets; + rx_bytes += bytes; + + st = per_cpu_ptr(ses->tx_stats, i); + + do { + start = u64_stats_fetch_begin_bh(&st->sync); + packets = st->packets; + bytes = st->bytes; + } while (u64_stats_fetch_retry_bh(&st->sync, start)); + + tx_packets += packets; + tx_bytes += bytes; + } + + stats->rx_packets = rx_packets; + stats->rx_bytes = rx_bytes; + stats->tx_packets = tx_packets; + stats->tx_bytes = tx_bytes; + + stats->rx_dropped = dev->stats.rx_dropped; + stats->tx_dropped = dev->stats.tx_dropped; + + return stats; +} +#endif + +static void ipoe_free_netdev(struct net_device *dev) +{ + struct ipoe_session *ses = netdev_priv(dev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + if (ses->rx_stats) + free_percpu(ses->rx_stats); + if (ses->tx_stats) + free_percpu(ses->tx_stats); +#endif + + free_netdev(dev); +} + static int ipoe_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned len) @@ -477,7 +660,7 @@ static void ipoe_netdev_setup(struct net_device *dev) #else dev->netdev_ops = &ipoe_netdev_ops; #endif - dev->destructor = free_netdev; + dev->destructor = ipoe_free_netdev; dev->type = ARPHRD_ETHER; dev->hard_header_len = 0; @@ -514,15 +697,27 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c dev_net_set(dev, &init_net); r = dev_alloc_name(dev, name); - if (r < 0) + if (r < 0) { + r = -ENOMEM; goto failed_free; + } ses = netdev_priv(dev); ses->dev = dev; ses->addr = addr; ses->peer_addr = peer_addr; ses->link_dev = link_dev; + ses->l3 = 1; memcpy(ses->hwaddr, hwaddr, ETH_ALEN); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + ses->rx_stats = alloc_percpu(struct ipoe_stats); + ses->tx_stats = alloc_percpu(struct ipoe_stats); + if (!ses->rx_stats || !ses->tx_stats) { + r = -ENOMEM; + goto failed_free; + } +#endif + dev->features = link_dev->features; memcpy(dev->dev_addr, link_dev->dev_addr, ETH_ALEN); memcpy(dev->broadcast, link_dev->broadcast, ETH_ALEN); @@ -538,14 +733,16 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c goto failed_free; down(&ipoe_wlock); - atomic_inc(&ipoe_rlock); - atomic_set(&ipoe_update, NEED_UPDATE); - if (atomic_dec_and_test(&ipoe_rlock)) - atomic_set(&ipoe_update, UPDATE); - else { - while (atomic_read(&ipoe_update) != UPDATE) - schedule_timeout_uninterruptible(1); - } + + spin_lock_bh(&ipoe_lock); + if (ipoe_rcv_active == 0) + ipoe_update = UPDATE; + else + ipoe_update = BEGIN_UPDATE; + spin_unlock_bh(&ipoe_lock); + + while (ipoe_update != UPDATE) + schedule_timeout_uninterruptible(1); if (ipoe_lookup(peer_addr, &parent, &p)) r = -EEXIST; @@ -554,11 +751,19 @@ static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, c rb_insert_color(&ses->node, &ipoe_rbt); } - up(&ipoe_wlock); + spin_lock_bh(&ipoe_lock); + if (ipoe_rcv_active == 0) + ipoe_update = 0; + else + ipoe_update = END_UPDATE; + spin_unlock_bh(&ipoe_lock); + + while (ipoe_update != 0) + schedule_timeout_uninterruptible(1); - atomic_set(&ipoe_update, 0); + list_add_tail(&ses->entry, &ipoe_list); - tasklet_schedule(&ipoe_rq_tasklet); + up(&ipoe_wlock); return r; @@ -569,57 +774,40 @@ failed: return r; } -static struct ipoe_session *ipoe_lookup(__be32 addr, struct rb_node **r_parent, struct rb_node ***r_p) -{ - struct ipoe_session *ses; - struct rb_node **p = &ipoe_rbt.rb_node; - struct rb_node *parent = NULL; - - while (*p) { - parent = *p; - ses = rb_entry(parent, typeof(*ses), node); - if (addr < ses->peer_addr) - p = &(*p)->rb_left; - else if (addr > ses->peer_addr) - p = &(*p)->rb_right; - else - return ses; - } - - if (r_parent) { - *r_parent = parent; - *r_p = p; - } - - return NULL; -} - - - static int ipoe_delete(__be32 addr) { struct ipoe_session *ses; down(&ipoe_wlock); - atomic_inc(&ipoe_rlock); - atomic_set(&ipoe_update, NEED_UPDATE); - if (atomic_dec_and_test(&ipoe_rlock)) - atomic_set(&ipoe_update, UPDATE); - else { - while (atomic_read(&ipoe_update) != UPDATE) - schedule_timeout_uninterruptible(1); - } + spin_lock_bh(&ipoe_lock); + if (ipoe_rcv_active == 0) + ipoe_update = UPDATE; + else + ipoe_update = BEGIN_UPDATE; + spin_unlock_bh(&ipoe_lock); + + while (ipoe_update != UPDATE) + schedule_timeout_uninterruptible(1); ses = ipoe_lookup(addr, NULL, NULL); if (ses) rb_erase(&ses->node, &ipoe_rbt); - up(&ipoe_wlock); + spin_lock_bh(&ipoe_lock); + if (ipoe_rcv_active == 0) + ipoe_update = 0; + else + ipoe_update = END_UPDATE; + spin_unlock_bh(&ipoe_lock); + + while (ipoe_update != 0) + schedule_timeout_uninterruptible(1); - atomic_set(&ipoe_update, 0); + if (ses) + list_del(&ses->entry); - tasklet_schedule(&ipoe_rq_tasklet); + up(&ipoe_wlock); if (!ses) return -EINVAL; @@ -750,6 +938,9 @@ static struct genl_family ipoe_nl_family = { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) static const struct net_device_ops ipoe_netdev_ops = { .ndo_start_xmit = ipoe_xmit, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + .ndo_get_stats64 = ipoe_stats64, +#endif }; #endif @@ -806,10 +997,6 @@ static int __init ipoe_init(void) goto out; } - tasklet_init(&ipoe_rq_tasklet, ipoe_recv_rq, 0); - - skb_queue_head_init(&ipoe_rq); - dev_add_pack(&ip_packet_type); dev_add_pack(&arp_packet_type); |