Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / net / core / pktgen.c
index 043ea18..b632760 100644 (file)
 #include <asm/dma.h>
 #include <asm/div64.h>         /* do_div */
 
-#define VERSION        "2.74"
+#define VERSION        "2.75"
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
 #define MPLS_STACK_BOTTOM htonl(0x00000100)
 #define T_REMDEVALL   (1<<2)   /* Remove all devs */
 #define T_REMDEV      (1<<3)   /* Remove one dev */
 
+/* Xmit modes */
+#define M_START_XMIT           0       /* Default normal TX */
+#define M_NETIF_RECEIVE        1       /* Inject packets into stack */
+
 /* If lock -- protects updating of if_list */
-#define   if_lock(t)           spin_lock(&(t->if_lock));
-#define   if_unlock(t)           spin_unlock(&(t->if_lock));
+#define   if_lock(t)           mutex_lock(&(t->if_lock));
+#define   if_unlock(t)           mutex_unlock(&(t->if_lock));
 
 /* Used to help with determining the pkts on receive */
 #define PKTGEN_MAGIC 0xbe9be955
@@ -251,13 +255,14 @@ struct pktgen_dev {
         * we will do a random selection from within the range.
         */
        __u32 flags;
-       int removal_mark;       /* non-zero => the device is marked for
-                                * removal by worker thread */
-
+       int xmit_mode;
        int min_pkt_size;
        int max_pkt_size;
        int pkt_overhead;       /* overhead for MPLS, VLANs, IPSEC etc */
        int nfrags;
+       int removal_mark;       /* non-zero => the device is marked for
+                                * removal by worker thread */
+
        struct page *page;
        u64 delay;              /* nano-seconds */
 
@@ -268,7 +273,6 @@ struct pktgen_dev {
 
        /* runtime counters relating to clone_skb */
 
-       __u64 allocated_skbs;
        __u32 clone_count;
        int last_ok;            /* Was last skb sent?
                                 * Or a failed transmit of some sort?
@@ -418,7 +422,7 @@ struct pktgen_net {
 };
 
 struct pktgen_thread {
-       spinlock_t if_lock;             /* for list of devices */
+       struct mutex if_lock;           /* for list of devices */
        struct list_head if_list;       /* All device here */
        struct list_head th_list;
        struct task_struct *tsk;
@@ -507,7 +511,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
                pktgen_reset_all_threads(pn);
 
        else
-               pr_warn("Unknown command: %s\n", data);
+               return -EINVAL;
 
        return count;
 }
@@ -567,7 +571,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
                           "     dst_min: %s  dst_max: %s\n",
                           pkt_dev->dst_min, pkt_dev->dst_max);
                seq_printf(seq,
-                          "        src_min: %s  src_max: %s\n",
+                          "     src_min: %s  src_max: %s\n",
                           pkt_dev->src_min, pkt_dev->src_max);
        }
 
@@ -620,6 +624,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->node >= 0)
                seq_printf(seq, "     node: %d\n", pkt_dev->node);
 
+       if (pkt_dev->xmit_mode == M_NETIF_RECEIVE)
+               seq_puts(seq, "     xmit_mode: netif_receive\n");
+
        seq_puts(seq, "     Flags: ");
 
        if (pkt_dev->flags & F_IPV6)
@@ -1081,7 +1088,8 @@ static ssize_t pktgen_if_write(struct file *file,
                if (len < 0)
                        return len;
                if ((value > 0) &&
-                   (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+                   ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
+                    !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
                        return -ENOTSUPP;
                i += len;
                pkt_dev->clone_skb = value;
@@ -1134,7 +1142,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        return len;
 
                i += len;
-               if ((value > 1) &&
+               if ((value > 1) && (pkt_dev->xmit_mode == M_START_XMIT) &&
                    (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
                        return -ENOTSUPP;
                pkt_dev->burst = value < 1 ? 1 : value;
@@ -1160,6 +1168,45 @@ static ssize_t pktgen_if_write(struct file *file,
                        sprintf(pg_result, "ERROR: node not possible");
                return count;
        }
+       if (!strcmp(name, "xmit_mode")) {
+               char f[32];
+
+               memset(f, 0, 32);
+               len = strn_len(&user_buffer[i], sizeof(f) - 1);
+               if (len < 0)
+                       return len;
+
+               if (copy_from_user(f, &user_buffer[i], len))
+                       return -EFAULT;
+               i += len;
+
+               if (strcmp(f, "start_xmit") == 0) {
+                       pkt_dev->xmit_mode = M_START_XMIT;
+               } else if (strcmp(f, "netif_receive") == 0) {
+                       /* clone_skb set earlier, not supported in this mode */
+                       if (pkt_dev->clone_skb > 0)
+                               return -ENOTSUPP;
+
+                       pkt_dev->xmit_mode = M_NETIF_RECEIVE;
+
+                       /* make sure new packet is allocated every time
+                        * pktgen_xmit() is called
+                        */
+                       pkt_dev->last_ok = 1;
+
+                       /* override clone_skb if user passed default value
+                        * at module loading time
+                        */
+                       pkt_dev->clone_skb = 0;
+               } else {
+                       sprintf(pg_result,
+                               "xmit_mode -:%s:- unknown\nAvailable modes: %s",
+                               f, "start_xmit, netif_receive\n");
+                       return count;
+               }
+               sprintf(pg_result, "OK: xmit_mode=%s", f);
+               return count;
+       }
        if (!strcmp(name, "flag")) {
                char f[32];
                memset(f, 0, 32);
@@ -1267,6 +1314,9 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "NO_TIMESTAMP") == 0)
                        pkt_dev->flags |= F_NO_TIMESTAMP;
 
+               else if (strcmp(f, "!NO_TIMESTAMP") == 0)
+                       pkt_dev->flags &= ~F_NO_TIMESTAMP;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -1952,11 +2002,13 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d
 {
        struct pktgen_thread *t;
 
+       mutex_lock(&pktgen_thread_lock);
+
        list_for_each_entry(t, &pn->pktgen_threads, th_list) {
                struct pktgen_dev *pkt_dev;
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
+               if_lock(t);
+               list_for_each_entry(pkt_dev, &t->if_list, list) {
                        if (pkt_dev->odev != dev)
                                continue;
 
@@ -1971,8 +2023,9 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d
                                       dev->name);
                        break;
                }
-               rcu_read_unlock();
+               if_unlock(t);
        }
+       mutex_unlock(&pktgen_thread_lock);
 }
 
 static int pktgen_device_event(struct notifier_block *unused,
@@ -2212,8 +2265,6 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
                do {
                        set_current_state(TASK_INTERRUPTIBLE);
                        hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
-                       if (!hrtimer_active(&t.timer))
-                               t.task = NULL;
 
                        if (likely(t.task))
                                schedule();
@@ -2594,9 +2645,9 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
                struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
                int nhead = 0;
                if (x) {
-                       int ret;
-                       __u8 *eth;
+                       struct ethhdr *eth;
                        struct iphdr *iph;
+                       int ret;
 
                        nhead = x->props.header_len - skb_headroom(skb);
                        if (nhead > 0) {
@@ -2616,9 +2667,9 @@ static int process_ipsec(struct pktgen_dev *pkt_dev,
                                goto err;
                        }
                        /* restore ll */
-                       eth = (__u8 *) skb_push(skb, ETH_HLEN);
-                       memcpy(eth, pkt_dev->hh, 12);
-                       *(u16 *) &eth[12] = protocol;
+                       eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+                       memcpy(eth, pkt_dev->hh, 2 * ETH_ALEN);
+                       eth->h_proto = protocol;
 
                        /* Update IPv4 header len as well as checksum value */
                        iph = ip_hdr(skb);
@@ -2721,13 +2772,13 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
 }
 
 static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
-                                       struct pktgen_dev *pkt_dev,
-                                       unsigned int extralen)
+                                       struct pktgen_dev *pkt_dev)
 {
+       unsigned int extralen = LL_RESERVED_SPACE(dev);
        struct sk_buff *skb = NULL;
-       unsigned int size = pkt_dev->cur_pkt_size + 64 + extralen +
-                           pkt_dev->pkt_overhead;
+       unsigned int size;
 
+       size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
        if (pkt_dev->flags & F_NODE) {
                int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
 
@@ -2740,6 +2791,10 @@ static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
                 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
        }
 
+       /* the caller pre-fetches from skb->data and reserves for the mac hdr */
+       if (likely(skb))
+               skb_reserve(skb, extralen - 16);
+
        return skb;
 }
 
@@ -2771,16 +2826,14 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        mod_cur_headers(pkt_dev);
        queue_map = pkt_dev->cur_queue_map;
 
-       datalen = (odev->hard_header_len + 16) & ~0xf;
-
-       skb = pktgen_alloc_skb(odev, pkt_dev, datalen);
+       skb = pktgen_alloc_skb(odev, pkt_dev);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
        }
 
        prefetchw(skb->data);
-       skb_reserve(skb, datalen);
+       skb_reserve(skb, 16);
 
        /*  Reserve for ethernet and IP header  */
        eth = (__u8 *) skb_push(skb, 14);
@@ -2900,7 +2953,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        mod_cur_headers(pkt_dev);
        queue_map = pkt_dev->cur_queue_map;
 
-       skb = pktgen_alloc_skb(odev, pkt_dev, 16);
+       skb = pktgen_alloc_skb(odev, pkt_dev);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
@@ -3317,6 +3370,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
        unsigned int burst = ACCESS_ONCE(pkt_dev->burst);
        struct net_device *odev = pkt_dev->odev;
        struct netdev_queue *txq;
+       struct sk_buff *skb;
        int ret;
 
        /* If device is offline, then don't send */
@@ -3347,13 +3401,43 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                        return;
                }
                pkt_dev->last_pkt_size = pkt_dev->skb->len;
-               pkt_dev->allocated_skbs++;
                pkt_dev->clone_count = 0;       /* reset counter */
        }
 
        if (pkt_dev->delay && pkt_dev->last_ok)
                spin(pkt_dev, pkt_dev->next_tx);
 
+       if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
+               skb = pkt_dev->skb;
+               skb->protocol = eth_type_trans(skb, skb->dev);
+               atomic_add(burst, &skb->users);
+               local_bh_disable();
+               do {
+                       ret = netif_receive_skb(skb);
+                       if (ret == NET_RX_DROP)
+                               pkt_dev->errors++;
+                       pkt_dev->sofar++;
+                       pkt_dev->seq_num++;
+                       if (atomic_read(&skb->users) != burst) {
+                               /* skb was queued by rps/rfs or taps,
+                                * so cannot reuse this skb
+                                */
+                               atomic_sub(burst - 1, &skb->users);
+                               /* get out of the loop and wait
+                                * until skb is consumed
+                                */
+                               break;
+                       }
+                       /* skb was 'freed' by stack, so clean few
+                        * bits and reuse it
+                        */
+#ifdef CONFIG_NET_CLS_ACT
+                       skb->tc_verd = 0; /* reset reclass/redir ttl */
+#endif
+               } while (--burst > 0);
+               goto out; /* Skips xmit_mode M_START_XMIT */
+       }
+
        txq = skb_get_tx_queue(odev, pkt_dev->skb);
 
        local_bh_disable();
@@ -3401,6 +3485,7 @@ xmit_more:
 unlock:
        HARD_TX_UNLOCK(odev, txq);
 
+out:
        local_bh_enable();
 
        /* If pkt_dev->count is zero, then run forever */
@@ -3432,8 +3517,6 @@ static int pktgen_thread_worker(void *arg)
 
        set_freezable();
 
-       __set_current_state(TASK_RUNNING);
-
        while (!kthread_should_stop()) {
                pkt_dev = next_to_run(t);
 
@@ -3478,7 +3561,6 @@ static int pktgen_thread_worker(void *arg)
 
                try_to_freeze();
        }
-       set_current_state(TASK_INTERRUPTIBLE);
 
        pr_debug("%s stopping all device\n", t->tsk->comm);
        pktgen_stop(t);
@@ -3489,15 +3571,6 @@ static int pktgen_thread_worker(void *arg)
        pr_debug("%s removing thread\n", t->tsk->comm);
        pktgen_rem_thread(t);
 
-       /* Wait for kthread_stop */
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (kthread_should_stop())
-                       break;
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-
        return 0;
 }
 
@@ -3656,7 +3729,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
                return -ENOMEM;
        }
 
-       spin_lock_init(&t->if_lock);
+       mutex_init(&t->if_lock);
        t->cpu = cpu;
 
        INIT_LIST_HEAD(&t->if_list);
@@ -3689,6 +3762,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
        }
 
        t->net = pn;
+       get_task_struct(p);
        wake_up_process(p);
        wait_for_completion(&t->start_done);
 
@@ -3811,6 +3885,7 @@ static void __net_exit pg_net_exit(struct net *net)
                t = list_entry(q, struct pktgen_thread, th_list);
                list_del(&t->th_list);
                kthread_stop(t->tsk);
+               put_task_struct(t->tsk);
                kfree(t);
        }