These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / core / pktgen.c
index 043ea18..4da4d51 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));
@@ -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?
@@ -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",
@@ -2212,8 +2262,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();
@@ -2230,7 +2278,7 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
 
 static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
 {
-       pkt_dev->pkt_overhead = 0;
+       pkt_dev->pkt_overhead = LL_RESERVED_SPACE(pkt_dev->odev);
        pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
        pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
        pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
@@ -2594,9 +2642,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 +2664,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);
@@ -2740,6 +2788,9 @@ static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
                 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
        }
 
+       if (likely(skb))
+               skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
        return skb;
 }
 
@@ -3317,6 +3368,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 +3399,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 +3483,7 @@ xmit_more:
 unlock:
        HARD_TX_UNLOCK(odev, txq);
 
+out:
        local_bh_enable();
 
        /* If pkt_dev->count is zero, then run forever */
@@ -3432,8 +3515,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 +3559,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 +3569,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;
 }
 
@@ -3689,6 +3760,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 +3883,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);
        }