aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2013-07-25 12:12:18 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-28 01:16:36 -0400
commitc26bf4a51308c85a6f97628253b99767a84ff90a (patch)
tree5c59f55f34fe58225fd37789ce14689d2c4005b9 /net
parent82a54d0ebbee03a8dcf4e1e4016a53fed4d6c933 (diff)
pktgen: Add UDPCSUM flag to support UDP checksums
UDP checksums are optional, hence pktgen has been omitting them in favour of performance. The optional flag UDPCSUM enables UDP checksumming. If the output device supports hardware checksumming the skb is prepared and marked CHECKSUM_PARTIAL, otherwise the checksum is generated in software. Signed-off-by: Thomas Graf <tgraf@suug.ch> Cc: Eric Dumazet <edumazet@google.com> Cc: Ben Greear <greearb@candelatech.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/pktgen.c57
-rw-r--r--net/ipv4/udp.c3
2 files changed, 54 insertions, 6 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 9640972ec50e..48cebf2c3e7a 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -160,6 +160,7 @@
160#include <net/net_namespace.h> 160#include <net/net_namespace.h>
161#include <net/checksum.h> 161#include <net/checksum.h>
162#include <net/ipv6.h> 162#include <net/ipv6.h>
163#include <net/udp.h>
163#include <net/addrconf.h> 164#include <net/addrconf.h>
164#ifdef CONFIG_XFRM 165#ifdef CONFIG_XFRM
165#include <net/xfrm.h> 166#include <net/xfrm.h>
@@ -198,6 +199,7 @@
198#define F_QUEUE_MAP_RND (1<<13) /* queue map Random */ 199#define F_QUEUE_MAP_RND (1<<13) /* queue map Random */
199#define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */ 200#define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */
200#define F_NODE (1<<15) /* Node memory alloc*/ 201#define F_NODE (1<<15) /* Node memory alloc*/
202#define F_UDPCSUM (1<<16) /* Include UDP checksum */
201 203
202/* Thread control flag bits */ 204/* Thread control flag bits */
203#define T_STOP (1<<0) /* Stop run */ 205#define T_STOP (1<<0) /* Stop run */
@@ -631,6 +633,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
631 if (pkt_dev->flags & F_UDPDST_RND) 633 if (pkt_dev->flags & F_UDPDST_RND)
632 seq_printf(seq, "UDPDST_RND "); 634 seq_printf(seq, "UDPDST_RND ");
633 635
636 if (pkt_dev->flags & F_UDPCSUM)
637 seq_printf(seq, "UDPCSUM ");
638
634 if (pkt_dev->flags & F_MPLS_RND) 639 if (pkt_dev->flags & F_MPLS_RND)
635 seq_printf(seq, "MPLS_RND "); 640 seq_printf(seq, "MPLS_RND ");
636 641
@@ -1228,6 +1233,12 @@ static ssize_t pktgen_if_write(struct file *file,
1228 else if (strcmp(f, "!NODE_ALLOC") == 0) 1233 else if (strcmp(f, "!NODE_ALLOC") == 0)
1229 pkt_dev->flags &= ~F_NODE; 1234 pkt_dev->flags &= ~F_NODE;
1230 1235
1236 else if (strcmp(f, "UDPCSUM") == 0)
1237 pkt_dev->flags |= F_UDPCSUM;
1238
1239 else if (strcmp(f, "!UDPCSUM") == 0)
1240 pkt_dev->flags &= ~F_UDPCSUM;
1241
1231 else { 1242 else {
1232 sprintf(pg_result, 1243 sprintf(pg_result,
1233 "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 1244 "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -2733,7 +2744,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
2733 udph->source = htons(pkt_dev->cur_udp_src); 2744 udph->source = htons(pkt_dev->cur_udp_src);
2734 udph->dest = htons(pkt_dev->cur_udp_dst); 2745 udph->dest = htons(pkt_dev->cur_udp_dst);
2735 udph->len = htons(datalen + 8); /* DATA + udphdr */ 2746 udph->len = htons(datalen + 8); /* DATA + udphdr */
2736 udph->check = 0; /* No checksum */ 2747 udph->check = 0;
2737 2748
2738 iph->ihl = 5; 2749 iph->ihl = 5;
2739 iph->version = 4; 2750 iph->version = 4;
@@ -2752,6 +2763,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
2752 skb->protocol = protocol; 2763 skb->protocol = protocol;
2753 skb->dev = odev; 2764 skb->dev = odev;
2754 skb->pkt_type = PACKET_HOST; 2765 skb->pkt_type = PACKET_HOST;
2766
2767 if (!(pkt_dev->flags & F_UDPCSUM)) {
2768 skb->ip_summed = CHECKSUM_NONE;
2769 } else if (odev->features & NETIF_F_V4_CSUM) {
2770 skb->ip_summed = CHECKSUM_PARTIAL;
2771 skb->csum = 0;
2772 udp4_hwcsum(skb, udph->source, udph->dest);
2773 } else {
2774 __wsum csum = udp_csum(skb);
2775
2776 /* add protocol-dependent pseudo-header */
2777 udph->check = csum_tcpudp_magic(udph->source, udph->dest,
2778 datalen + 8, IPPROTO_UDP, csum);
2779
2780 if (udph->check == 0)
2781 udph->check = CSUM_MANGLED_0;
2782 }
2783
2755 pktgen_finalize_skb(pkt_dev, skb, datalen); 2784 pktgen_finalize_skb(pkt_dev, skb, datalen);
2756 2785
2757#ifdef CONFIG_XFRM 2786#ifdef CONFIG_XFRM
@@ -2768,7 +2797,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2768 struct sk_buff *skb = NULL; 2797 struct sk_buff *skb = NULL;
2769 __u8 *eth; 2798 __u8 *eth;
2770 struct udphdr *udph; 2799 struct udphdr *udph;
2771 int datalen; 2800 int datalen, udplen;
2772 struct ipv6hdr *iph; 2801 struct ipv6hdr *iph;
2773 __be16 protocol = htons(ETH_P_IPV6); 2802 __be16 protocol = htons(ETH_P_IPV6);
2774 __be32 *mpls; 2803 __be32 *mpls;
@@ -2844,10 +2873,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2844 net_info_ratelimited("increased datalen to %d\n", datalen); 2873 net_info_ratelimited("increased datalen to %d\n", datalen);
2845 } 2874 }
2846 2875
2876 udplen = datalen + sizeof(struct udphdr);
2847 udph->source = htons(pkt_dev->cur_udp_src); 2877 udph->source = htons(pkt_dev->cur_udp_src);
2848 udph->dest = htons(pkt_dev->cur_udp_dst); 2878 udph->dest = htons(pkt_dev->cur_udp_dst);
2849 udph->len = htons(datalen + sizeof(struct udphdr)); 2879 udph->len = htons(udplen);
2850 udph->check = 0; /* No checksum */ 2880 udph->check = 0;
2851 2881
2852 *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 2882 *(__be32 *) iph = htonl(0x60000000); /* Version + flow */
2853 2883
@@ -2858,7 +2888,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2858 2888
2859 iph->hop_limit = 32; 2889 iph->hop_limit = 32;
2860 2890
2861 iph->payload_len = htons(sizeof(struct udphdr) + datalen); 2891 iph->payload_len = htons(udplen);
2862 iph->nexthdr = IPPROTO_UDP; 2892 iph->nexthdr = IPPROTO_UDP;
2863 2893
2864 iph->daddr = pkt_dev->cur_in6_daddr; 2894 iph->daddr = pkt_dev->cur_in6_daddr;
@@ -2868,6 +2898,23 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2868 skb->dev = odev; 2898 skb->dev = odev;
2869 skb->pkt_type = PACKET_HOST; 2899 skb->pkt_type = PACKET_HOST;
2870 2900
2901 if (!(pkt_dev->flags & F_UDPCSUM)) {
2902 skb->ip_summed = CHECKSUM_NONE;
2903 } else if (odev->features & NETIF_F_V6_CSUM) {
2904 skb->ip_summed = CHECKSUM_PARTIAL;
2905 skb->csum_start = skb_transport_header(skb) - skb->head;
2906 skb->csum_offset = offsetof(struct udphdr, check);
2907 udph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, 0);
2908 } else {
2909 __wsum csum = udp_csum(skb);
2910
2911 /* add protocol-dependent pseudo-header */
2912 udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr, udplen, IPPROTO_UDP, csum);
2913
2914 if (udph->check == 0)
2915 udph->check = CSUM_MANGLED_0;
2916 }
2917
2871 pktgen_finalize_skb(pkt_dev, skb, datalen); 2918 pktgen_finalize_skb(pkt_dev, skb, datalen);
2872 2919
2873 return skb; 2920 return skb;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 766e6bab9113..9e88af0e8ab0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -704,7 +704,7 @@ EXPORT_SYMBOL(udp_flush_pending_frames);
704 * @src: source IP address 704 * @src: source IP address
705 * @dst: destination IP address 705 * @dst: destination IP address
706 */ 706 */
707static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) 707void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
708{ 708{
709 struct udphdr *uh = udp_hdr(skb); 709 struct udphdr *uh = udp_hdr(skb);
710 struct sk_buff *frags = skb_shinfo(skb)->frag_list; 710 struct sk_buff *frags = skb_shinfo(skb)->frag_list;
@@ -740,6 +740,7 @@ static void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst)
740 uh->check = CSUM_MANGLED_0; 740 uh->check = CSUM_MANGLED_0;
741 } 741 }
742} 742}
743EXPORT_SYMBOL_GPL(udp4_hwcsum);
743 744
744static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) 745static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
745{ 746{