]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/core/pktgen.c
pktgen: add needed include file
[karo-tx-linux.git] / net / core / pktgen.c
index 11f2704c3810d54b3539daddea36d50ef230636f..261357a663001ccf98a92ba5f6d0f6ad141c7ce3 100644 (file)
 #include <net/net_namespace.h>
 #include <net/checksum.h>
 #include <net/ipv6.h>
+#include <net/udp.h>
+#include <net/ip6_checksum.h>
 #include <net/addrconf.h>
 #ifdef CONFIG_XFRM
 #include <net/xfrm.h>
 #define F_QUEUE_MAP_RND (1<<13)        /* queue map Random */
 #define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
 #define F_NODE          (1<<15)        /* Node memory alloc*/
+#define F_UDPCSUM       (1<<16)        /* Include UDP checksum */
 
 /* Thread control flag bits */
 #define T_STOP        (1<<0)   /* Stop run */
@@ -631,6 +634,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_UDPDST_RND)
                seq_printf(seq, "UDPDST_RND  ");
 
+       if (pkt_dev->flags & F_UDPCSUM)
+               seq_printf(seq, "UDPCSUM  ");
+
        if (pkt_dev->flags & F_MPLS_RND)
                seq_printf(seq,  "MPLS_RND  ");
 
@@ -1228,6 +1234,12 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!NODE_ALLOC") == 0)
                        pkt_dev->flags &= ~F_NODE;
 
+               else if (strcmp(f, "UDPCSUM") == 0)
+                       pkt_dev->flags |= F_UDPCSUM;
+
+               else if (strcmp(f, "!UDPCSUM") == 0)
+                       pkt_dev->flags &= ~F_UDPCSUM;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -1921,7 +1933,7 @@ static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *d
 static int pktgen_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
-       struct net_device *dev = ptr;
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id);
 
        if (pn->pktgen_exiting)
@@ -2627,6 +2639,29 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
        pgh->tv_usec = htonl(timestamp.tv_usec);
 }
 
+static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
+                                       struct pktgen_dev *pkt_dev,
+                                       unsigned int extralen)
+{
+       struct sk_buff *skb = NULL;
+       unsigned int 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();
+
+               skb = __alloc_skb(NET_SKB_PAD + size, GFP_NOWAIT, 0, node);
+               if (likely(skb)) {
+                       skb_reserve(skb, NET_SKB_PAD);
+                       skb->dev = dev;
+               }
+       } else {
+                skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
+       }
+
+       return skb;
+}
+
 static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                                        struct pktgen_dev *pkt_dev)
 {
@@ -2657,32 +2692,13 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 
        datalen = (odev->hard_header_len + 16) & ~0xf;
 
-       if (pkt_dev->flags & F_NODE) {
-               int node;
-
-               if (pkt_dev->node >= 0)
-                       node = pkt_dev->node;
-               else
-                       node =  numa_node_id();
-
-               skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64
-                                 + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node);
-               if (likely(skb)) {
-                       skb_reserve(skb, NET_SKB_PAD);
-                       skb->dev = odev;
-               }
-       }
-       else
-         skb = __netdev_alloc_skb(odev,
-                                  pkt_dev->cur_pkt_size + 64
-                                  + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
-
+       skb = pktgen_alloc_skb(odev, pkt_dev, datalen);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
        }
-       prefetchw(skb->data);
 
+       prefetchw(skb->data);
        skb_reserve(skb, datalen);
 
        /*  Reserve for ethernet and IP header  */
@@ -2708,15 +2724,15 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                *vlan_encapsulated_proto = htons(ETH_P_IP);
        }
 
-       skb->network_header = skb->tail;
-       skb->transport_header = skb->network_header + sizeof(struct iphdr);
-       skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
+       skb_set_mac_header(skb, 0);
+       skb_set_network_header(skb, skb->len);
+       iph = (struct iphdr *) skb_put(skb, sizeof(struct iphdr));
+
+       skb_set_transport_header(skb, skb->len);
+       udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr));
        skb_set_queue_mapping(skb, queue_map);
        skb->priority = pkt_dev->skb_priority;
 
-       iph = ip_hdr(skb);
-       udph = udp_hdr(skb);
-
        memcpy(eth, pkt_dev->hh, 12);
        *(__be16 *) & eth[12] = protocol;
 
@@ -2729,7 +2745,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
        udph->len = htons(datalen + 8); /* DATA + udphdr */
-       udph->check = 0;        /* No checksum */
+       udph->check = 0;
 
        iph->ihl = 5;
        iph->version = 4;
@@ -2743,13 +2759,28 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph->frag_off = 0;
        iplen = 20 + 8 + datalen;
        iph->tot_len = htons(iplen);
-       iph->check = 0;
-       iph->check = ip_fast_csum((void *)iph, iph->ihl);
+       ip_send_check(iph);
        skb->protocol = protocol;
-       skb->mac_header = (skb->network_header - ETH_HLEN -
-                          pkt_dev->pkt_overhead);
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
+
+       if (!(pkt_dev->flags & F_UDPCSUM)) {
+               skb->ip_summed = CHECKSUM_NONE;
+       } else if (odev->features & NETIF_F_V4_CSUM) {
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               skb->csum = 0;
+               udp4_hwcsum(skb, udph->source, udph->dest);
+       } else {
+               __wsum csum = udp_csum(skb);
+
+               /* add protocol-dependent pseudo-header */
+               udph->check = csum_tcpudp_magic(udph->source, udph->dest,
+                                               datalen + 8, IPPROTO_UDP, csum);
+
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+       }
+
        pktgen_finalize_skb(pkt_dev, skb, datalen);
 
 #ifdef CONFIG_XFRM
@@ -2766,7 +2797,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        struct sk_buff *skb = NULL;
        __u8 *eth;
        struct udphdr *udph;
-       int datalen;
+       int datalen, udplen;
        struct ipv6hdr *iph;
        __be16 protocol = htons(ETH_P_IPV6);
        __be32 *mpls;
@@ -2788,15 +2819,13 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        mod_cur_headers(pkt_dev);
        queue_map = pkt_dev->cur_queue_map;
 
-       skb = __netdev_alloc_skb(odev,
-                                pkt_dev->cur_pkt_size + 64
-                                + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT);
+       skb = pktgen_alloc_skb(odev, pkt_dev, 16);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
        }
-       prefetchw(skb->data);
 
+       prefetchw(skb->data);
        skb_reserve(skb, 16);
 
        /*  Reserve for ethernet and IP header  */
@@ -2822,13 +2851,14 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                *vlan_encapsulated_proto = htons(ETH_P_IPV6);
        }
 
-       skb->network_header = skb->tail;
-       skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
-       skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
+       skb_set_mac_header(skb, 0);
+       skb_set_network_header(skb, skb->len);
+       iph = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
+
+       skb_set_transport_header(skb, skb->len);
+       udph = (struct udphdr *) skb_put(skb, sizeof(struct udphdr));
        skb_set_queue_mapping(skb, queue_map);
        skb->priority = pkt_dev->skb_priority;
-       iph = ipv6_hdr(skb);
-       udph = udp_hdr(skb);
 
        memcpy(eth, pkt_dev->hh, 12);
        *(__be16 *) &eth[12] = protocol;
@@ -2843,10 +2873,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                net_info_ratelimited("increased datalen to %d\n", datalen);
        }
 
+       udplen = datalen + sizeof(struct udphdr);
        udph->source = htons(pkt_dev->cur_udp_src);
        udph->dest = htons(pkt_dev->cur_udp_dst);
-       udph->len = htons(datalen + sizeof(struct udphdr));
-       udph->check = 0;        /* No checksum */
+       udph->len = htons(udplen);
+       udph->check = 0;
 
        *(__be32 *) iph = htonl(0x60000000);    /* Version + flow */
 
@@ -2857,18 +2888,33 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
 
        iph->hop_limit = 32;
 
-       iph->payload_len = htons(sizeof(struct udphdr) + datalen);
+       iph->payload_len = htons(udplen);
        iph->nexthdr = IPPROTO_UDP;
 
        iph->daddr = pkt_dev->cur_in6_daddr;
        iph->saddr = pkt_dev->cur_in6_saddr;
 
-       skb->mac_header = (skb->network_header - ETH_HLEN -
-                          pkt_dev->pkt_overhead);
        skb->protocol = protocol;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
+       if (!(pkt_dev->flags & F_UDPCSUM)) {
+               skb->ip_summed = CHECKSUM_NONE;
+       } else if (odev->features & NETIF_F_V6_CSUM) {
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               skb->csum_start = skb_transport_header(skb) - skb->head;
+               skb->csum_offset = offsetof(struct udphdr, check);
+               udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
+       } else {
+               __wsum csum = udp_csum(skb);
+
+               /* add protocol-dependent pseudo-header */
+               udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
+
+               if (udph->check == 0)
+                       udph->check = CSUM_MANGLED_0;
+       }
+
        pktgen_finalize_skb(pkt_dev, skb, datalen);
 
        return skb;