Merge branch 'for-linus' of git://git.infradead.org/users/eparis/selinux into for...
[firefly-linux-kernel-4.4.55.git] / net / core / pktgen.c
index a9e7fc4c461fa6679c39a51b214d242e1c22b873..aeeece72b72fa25d29dfd3162a2f9c3a8ef6fcbd 100644 (file)
@@ -251,6 +251,7 @@ struct pktgen_dev {
        int max_pkt_size;       /* = ETH_ZLEN; */
        int pkt_overhead;       /* overhead for MPLS, VLANs, IPSEC etc */
        int nfrags;
+       struct page *page;
        u64 delay;              /* nano-seconds */
 
        __u64 count;            /* Default No packets to send */
@@ -1134,6 +1135,10 @@ static ssize_t pktgen_if_write(struct file *file,
                if (node_possible(value)) {
                        pkt_dev->node = value;
                        sprintf(pg_result, "OK: node=%d", pkt_dev->node);
+                       if (pkt_dev->page) {
+                               put_page(pkt_dev->page);
+                               pkt_dev->page = NULL;
+                       }
                }
                else
                        sprintf(pg_result, "ERROR: node not possible");
@@ -2605,6 +2610,89 @@ static inline __be16 build_tci(unsigned int id, unsigned int cfi,
        return htons(id | (cfi << 12) | (prio << 13));
 }
 
+static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
+                               int datalen)
+{
+       struct timeval timestamp;
+       struct pktgen_hdr *pgh;
+
+       pgh = (struct pktgen_hdr *)skb_put(skb, sizeof(*pgh));
+       datalen -= sizeof(*pgh);
+
+       if (pkt_dev->nfrags <= 0) {
+               memset(skb_put(skb, datalen), 0, datalen);
+       } else {
+               int frags = pkt_dev->nfrags;
+               int i, len;
+
+
+               if (frags > MAX_SKB_FRAGS)
+                       frags = MAX_SKB_FRAGS;
+               len = datalen - frags * PAGE_SIZE;
+               if (len > 0) {
+                       memset(skb_put(skb, len), 0, len);
+                       datalen = frags * PAGE_SIZE;
+               }
+
+               i = 0;
+               while (datalen > 0) {
+                       if (unlikely(!pkt_dev->page)) {
+                               int node = numa_node_id();
+
+                               if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE))
+                                       node = pkt_dev->node;
+                               pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
+                               if (!pkt_dev->page)
+                                       break;
+                       }
+                       skb_shinfo(skb)->frags[i].page = pkt_dev->page;
+                       get_page(pkt_dev->page);
+                       skb_shinfo(skb)->frags[i].page_offset = 0;
+                       skb_shinfo(skb)->frags[i].size =
+                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+                       datalen -= skb_shinfo(skb)->frags[i].size;
+                       skb->len += skb_shinfo(skb)->frags[i].size;
+                       skb->data_len += skb_shinfo(skb)->frags[i].size;
+                       i++;
+                       skb_shinfo(skb)->nr_frags = i;
+               }
+
+               while (i < frags) {
+                       int rem;
+
+                       if (i == 0)
+                               break;
+
+                       rem = skb_shinfo(skb)->frags[i - 1].size / 2;
+                       if (rem == 0)
+                               break;
+
+                       skb_shinfo(skb)->frags[i - 1].size -= rem;
+
+                       skb_shinfo(skb)->frags[i] =
+                           skb_shinfo(skb)->frags[i - 1];
+                       get_page(skb_shinfo(skb)->frags[i].page);
+                       skb_shinfo(skb)->frags[i].page =
+                           skb_shinfo(skb)->frags[i - 1].page;
+                       skb_shinfo(skb)->frags[i].page_offset +=
+                           skb_shinfo(skb)->frags[i - 1].size;
+                       skb_shinfo(skb)->frags[i].size = rem;
+                       i++;
+                       skb_shinfo(skb)->nr_frags = i;
+               }
+       }
+
+       /* Stamp the time, and sequence number,
+        * convert them to network byte order
+        */
+       pgh->pgh_magic = htonl(PKTGEN_MAGIC);
+       pgh->seq_num = htonl(pkt_dev->seq_num);
+
+       do_gettimeofday(&timestamp);
+       pgh->tv_sec = htonl(timestamp.tv_sec);
+       pgh->tv_usec = htonl(timestamp.tv_usec);
+}
+
 static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                                        struct pktgen_dev *pkt_dev)
 {
@@ -2613,7 +2701,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        struct udphdr *udph;
        int datalen, iplen;
        struct iphdr *iph;
-       struct pktgen_hdr *pgh = NULL;
        __be16 protocol = htons(ETH_P_IP);
        __be32 *mpls;
        __be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
@@ -2729,76 +2816,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                           pkt_dev->pkt_overhead);
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
-
-       if (pkt_dev->nfrags <= 0) {
-               pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
-               memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr));
-       } else {
-               int frags = pkt_dev->nfrags;
-               int i, len;
-
-               pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
-
-               if (frags > MAX_SKB_FRAGS)
-                       frags = MAX_SKB_FRAGS;
-               if (datalen > frags * PAGE_SIZE) {
-                       len = datalen - frags * PAGE_SIZE;
-                       memset(skb_put(skb, len), 0, len);
-                       datalen = frags * PAGE_SIZE;
-               }
-
-               i = 0;
-               while (datalen > 0) {
-                       struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
-                       skb_shinfo(skb)->frags[i].page = page;
-                       skb_shinfo(skb)->frags[i].page_offset = 0;
-                       skb_shinfo(skb)->frags[i].size =
-                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
-                       datalen -= skb_shinfo(skb)->frags[i].size;
-                       skb->len += skb_shinfo(skb)->frags[i].size;
-                       skb->data_len += skb_shinfo(skb)->frags[i].size;
-                       i++;
-                       skb_shinfo(skb)->nr_frags = i;
-               }
-
-               while (i < frags) {
-                       int rem;
-
-                       if (i == 0)
-                               break;
-
-                       rem = skb_shinfo(skb)->frags[i - 1].size / 2;
-                       if (rem == 0)
-                               break;
-
-                       skb_shinfo(skb)->frags[i - 1].size -= rem;
-
-                       skb_shinfo(skb)->frags[i] =
-                           skb_shinfo(skb)->frags[i - 1];
-                       get_page(skb_shinfo(skb)->frags[i].page);
-                       skb_shinfo(skb)->frags[i].page =
-                           skb_shinfo(skb)->frags[i - 1].page;
-                       skb_shinfo(skb)->frags[i].page_offset +=
-                           skb_shinfo(skb)->frags[i - 1].size;
-                       skb_shinfo(skb)->frags[i].size = rem;
-                       i++;
-                       skb_shinfo(skb)->nr_frags = i;
-               }
-       }
-
-       /* Stamp the time, and sequence number,
-        * convert them to network byte order
-        */
-       if (pgh) {
-               struct timeval timestamp;
-
-               pgh->pgh_magic = htonl(PKTGEN_MAGIC);
-               pgh->seq_num = htonl(pkt_dev->seq_num);
-
-               do_gettimeofday(&timestamp);
-               pgh->tv_sec = htonl(timestamp.tv_sec);
-               pgh->tv_usec = htonl(timestamp.tv_usec);
-       }
+       pktgen_finalize_skb(pkt_dev, skb, datalen);
 
 #ifdef CONFIG_XFRM
        if (!process_ipsec(pkt_dev, skb, protocol))
@@ -2980,7 +2998,6 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        struct udphdr *udph;
        int datalen;
        struct ipv6hdr *iph;
-       struct pktgen_hdr *pgh = NULL;
        __be16 protocol = htons(ETH_P_IPV6);
        __be32 *mpls;
        __be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
@@ -3083,75 +3100,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
-       if (pkt_dev->nfrags <= 0)
-               pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
-       else {
-               int frags = pkt_dev->nfrags;
-               int i;
-
-               pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
-
-               if (frags > MAX_SKB_FRAGS)
-                       frags = MAX_SKB_FRAGS;
-               if (datalen > frags * PAGE_SIZE) {
-                       skb_put(skb, datalen - frags * PAGE_SIZE);
-                       datalen = frags * PAGE_SIZE;
-               }
-
-               i = 0;
-               while (datalen > 0) {
-                       struct page *page = alloc_pages(GFP_KERNEL, 0);
-                       skb_shinfo(skb)->frags[i].page = page;
-                       skb_shinfo(skb)->frags[i].page_offset = 0;
-                       skb_shinfo(skb)->frags[i].size =
-                           (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
-                       datalen -= skb_shinfo(skb)->frags[i].size;
-                       skb->len += skb_shinfo(skb)->frags[i].size;
-                       skb->data_len += skb_shinfo(skb)->frags[i].size;
-                       i++;
-                       skb_shinfo(skb)->nr_frags = i;
-               }
-
-               while (i < frags) {
-                       int rem;
-
-                       if (i == 0)
-                               break;
-
-                       rem = skb_shinfo(skb)->frags[i - 1].size / 2;
-                       if (rem == 0)
-                               break;
-
-                       skb_shinfo(skb)->frags[i - 1].size -= rem;
-
-                       skb_shinfo(skb)->frags[i] =
-                           skb_shinfo(skb)->frags[i - 1];
-                       get_page(skb_shinfo(skb)->frags[i].page);
-                       skb_shinfo(skb)->frags[i].page =
-                           skb_shinfo(skb)->frags[i - 1].page;
-                       skb_shinfo(skb)->frags[i].page_offset +=
-                           skb_shinfo(skb)->frags[i - 1].size;
-                       skb_shinfo(skb)->frags[i].size = rem;
-                       i++;
-                       skb_shinfo(skb)->nr_frags = i;
-               }
-       }
-
-       /* Stamp the time, and sequence number,
-        * convert them to network byte order
-        * should we update cloned packets too ?
-        */
-       if (pgh) {
-               struct timeval timestamp;
-
-               pgh->pgh_magic = htonl(PKTGEN_MAGIC);
-               pgh->seq_num = htonl(pkt_dev->seq_num);
-
-               do_gettimeofday(&timestamp);
-               pgh->tv_sec = htonl(timestamp.tv_sec);
-               pgh->tv_usec = htonl(timestamp.tv_usec);
-       }
-       /* pkt_dev->seq_num++; FF: you really mean this? */
+       pktgen_finalize_skb(pkt_dev, skb, datalen);
 
        return skb;
 }
@@ -3321,7 +3270,7 @@ static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
                                    pkt_dev->started_at);
        ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
 
-       p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
+       p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
                     (unsigned long long)ktime_to_us(elapsed),
                     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
                     (unsigned long long)ktime_to_us(idle),
@@ -3812,7 +3761,10 @@ static int __init pktgen_create_thread(int cpu)
        list_add_tail(&t->th_list, &pktgen_threads);
        init_completion(&t->start_done);
 
-       p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
+       p = kthread_create_on_node(pktgen_thread_worker,
+                                  t,
+                                  cpu_to_node(cpu),
+                                  "kpktgend_%d", cpu);
        if (IS_ERR(p)) {
                pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
                list_del(&t->th_list);
@@ -3884,6 +3836,8 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        free_SAs(pkt_dev);
 #endif
        vfree(pkt_dev->flows);
+       if (pkt_dev->page)
+               put_page(pkt_dev->page);
        kfree(pkt_dev);
        return 0;
 }