static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) { struct net_device *odev = pkt_dev->odev; int (*xmit)(struct sk_buff *, struct net_device *) = odev->netdev_ops->ndo_start_xmit; struct netdev_queue *txq; __u64 idle_start = 0; u16 queue_map; int ret; if (pkt_dev->delay_us || pkt_dev->delay_ns) { u64 now; now = getCurUs(); if (now < pkt_dev->next_tx_us) spin(pkt_dev, pkt_dev->next_tx_us); /* This is max DELAY, this has special meaning of * "never transmit" */ if (pkt_dev->delay_us == 0x7FFFFFFF) { pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us; pkt_dev->next_tx_ns = pkt_dev->delay_ns; goto out; } } if (!pkt_dev->skb) { set_cur_queue_map(pkt_dev); queue_map = pkt_dev->cur_queue_map; } else { queue_map = skb_get_queue_mapping(pkt_dev->skb); } txq = netdev_get_tx_queue(odev, queue_map); if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq) || need_resched()) { idle_start = getCurUs(); if (!netif_running(odev)) { pktgen_stop_device(pkt_dev); kfree_skb(pkt_dev->skb); pkt_dev->skb = NULL; goto out; } if (need_resched()) schedule(); pkt_dev->idle_acc += getCurUs() - idle_start; if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)) { pkt_dev->next_tx_us = getCurUs(); /* TODO */ pkt_dev->next_tx_ns = 0; goto out; /* Try the next interface */ } } if (pkt_dev->last_ok || !pkt_dev->skb) { if ((++pkt_dev->clone_count >= pkt_dev->clone_skb) || (!pkt_dev->skb)) { /* build a new pkt */ kfree_skb(pkt_dev->skb); pkt_dev->skb = fill_packet(odev, pkt_dev); if (pkt_dev->skb == NULL) { printk(KERN_ERR "pktgen: ERROR: couldn't " "allocate skb in fill_packet.\n"); schedule(); pkt_dev->clone_count--; /* back out increment, OOM */ goto out; } pkt_dev->allocated_skbs++; pkt_dev->clone_count = 0; /* reset counter */ } } /* fill_packet() might have changed the queue */ queue_map = skb_get_queue_mapping(pkt_dev->skb); txq = netdev_get_tx_queue(odev, queue_map); __netif_tx_lock_bh(txq); if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq)) { atomic_inc(&(pkt_dev->skb->users)); retry_now: ret = (*xmit)(pkt_dev->skb, odev); if (likely(ret == NETDEV_TX_OK)) { pkt_dev->last_ok = 1; pkt_dev->sofar++; pkt_dev->seq_num++; pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; } else if (ret == NETDEV_TX_LOCKED && (odev->features & NETIF_F_LLTX)) { cpu_relax(); goto retry_now; } else { /* Retry it next time */ atomic_dec(&(pkt_dev->skb->users)); if (debug && net_ratelimit()) printk(KERN_INFO "pktgen: Hard xmit error\n"); pkt_dev->errors++; pkt_dev->last_ok = 0; } pkt_dev->next_tx_us = getCurUs(); pkt_dev->next_tx_ns = 0; pkt_dev->next_tx_us += pkt_dev->delay_us; pkt_dev->next_tx_ns += pkt_dev->delay_ns; if (pkt_dev->next_tx_ns > 1000) { pkt_dev->next_tx_us++; pkt_dev->next_tx_ns -= 1000; } } else { /* Retry it next time */ pkt_dev->last_ok = 0; pkt_dev->next_tx_us = getCurUs(); /* TODO */ pkt_dev->next_tx_ns = 0; } __netif_tx_unlock_bh(txq); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { if (atomic_read(&(pkt_dev->skb->users)) != 1) { idle_start = getCurUs(); while (atomic_read(&(pkt_dev->skb->users)) != 1) { if (signal_pending(current)) { break; } schedule(); } pkt_dev->idle_acc += getCurUs() - idle_start; } /* Done with this */ pktgen_stop_device(pkt_dev); kfree_skb(pkt_dev->skb); pkt_dev->skb = NULL; } out:; } /* * Main loop of the thread goes here */ static int pktgen_thread_worker(void *arg) { DEFINE_WAIT(wait); struct pktgen_thread *t = arg; struct pktgen_dev *pkt_dev = NULL; int cpu = t->cpu; BUG_ON(smp_processor_id() != cpu); init_waitqueue_head(&t->queue); complete(&t->start_done); pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); set_current_state(TASK_INTERRUPTIBLE); set_freezable(); while (!kthread_should_stop()) { pkt_dev = next_to_run(t); if (!pkt_dev && (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV)) == 0) { prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); finish_wait(&(t->queue), &wait); } __set_current_state(TASK_RUNNING); if (pkt_dev) pktgen_xmit(pkt_dev); if (t->control & T_STOP) { pktgen_stop(t); t->control &= ~(T_STOP); } if (t->control & T_RUN) { pktgen_run(t); t->control &= ~(T_RUN); } if (t->control & T_REMDEVALL) { pktgen_rem_all_ifs(t); t->control &= ~(T_REMDEVALL); } if (t->control & T_REMDEV) { pktgen_rem_one_if(t); t->control &= ~(T_REMDEV); } try_to_freeze(); set_current_state(TASK_INTERRUPTIBLE); } pr_debug("pktgen: %s stopping all device\n", t->tsk->comm); pktgen_stop(t); pr_debug("pktgen: %s removing all device\n", t->tsk->comm); pktgen_rem_all_ifs(t); pr_debug("pktgen: %s removing thread.\n", t->tsk->comm); pktgen_rem_thread(t); return 0; } |