diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/pktgen.c | 158 |
1 files changed, 147 insertions, 11 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8eedaedba743..c23e9c06ee23 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -106,6 +106,9 @@ | |||
106 | * | 106 | * |
107 | * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> | 107 | * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> |
108 | * 050103 | 108 | * 050103 |
109 | * | ||
110 | * MPLS support by Steven Whitehouse <steve@chygwyn.com> | ||
111 | * | ||
109 | */ | 112 | */ |
110 | #include <linux/sys.h> | 113 | #include <linux/sys.h> |
111 | #include <linux/types.h> | 114 | #include <linux/types.h> |
@@ -154,7 +157,7 @@ | |||
154 | #include <asm/div64.h> /* do_div */ | 157 | #include <asm/div64.h> /* do_div */ |
155 | #include <asm/timex.h> | 158 | #include <asm/timex.h> |
156 | 159 | ||
157 | #define VERSION "pktgen v2.66: Packet Generator for packet performance testing.\n" | 160 | #define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n" |
158 | 161 | ||
159 | /* #define PG_DEBUG(a) a */ | 162 | /* #define PG_DEBUG(a) a */ |
160 | #define PG_DEBUG(a) | 163 | #define PG_DEBUG(a) |
@@ -162,6 +165,8 @@ | |||
162 | /* The buckets are exponential in 'width' */ | 165 | /* The buckets are exponential in 'width' */ |
163 | #define LAT_BUCKETS_MAX 32 | 166 | #define LAT_BUCKETS_MAX 32 |
164 | #define IP_NAME_SZ 32 | 167 | #define IP_NAME_SZ 32 |
168 | #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ | ||
169 | #define MPLS_STACK_BOTTOM __constant_htonl(0x00000100) | ||
165 | 170 | ||
166 | /* Device flag bits */ | 171 | /* Device flag bits */ |
167 | #define F_IPSRC_RND (1<<0) /* IP-Src Random */ | 172 | #define F_IPSRC_RND (1<<0) /* IP-Src Random */ |
@@ -172,6 +177,7 @@ | |||
172 | #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ | 177 | #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ |
173 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ | 178 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ |
174 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ | 179 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ |
180 | #define F_MPLS_RND (1<<8) /* Random MPLS labels */ | ||
175 | 181 | ||
176 | /* Thread control flag bits */ | 182 | /* Thread control flag bits */ |
177 | #define T_TERMINATE (1<<0) | 183 | #define T_TERMINATE (1<<0) |
@@ -278,6 +284,10 @@ struct pktgen_dev { | |||
278 | __u16 udp_dst_min; /* inclusive, dest UDP port */ | 284 | __u16 udp_dst_min; /* inclusive, dest UDP port */ |
279 | __u16 udp_dst_max; /* exclusive, dest UDP port */ | 285 | __u16 udp_dst_max; /* exclusive, dest UDP port */ |
280 | 286 | ||
287 | /* MPLS */ | ||
288 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ | ||
289 | __be32 labels[MAX_MPLS_LABELS]; | ||
290 | |||
281 | __u32 src_mac_count; /* How many MACs to iterate through */ | 291 | __u32 src_mac_count; /* How many MACs to iterate through */ |
282 | __u32 dst_mac_count; /* How many MACs to iterate through */ | 292 | __u32 dst_mac_count; /* How many MACs to iterate through */ |
283 | 293 | ||
@@ -623,9 +633,19 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
623 | pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); | 633 | pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); |
624 | 634 | ||
625 | seq_printf(seq, | 635 | seq_printf(seq, |
626 | " src_mac_count: %d dst_mac_count: %d \n Flags: ", | 636 | " src_mac_count: %d dst_mac_count: %d\n", |
627 | pkt_dev->src_mac_count, pkt_dev->dst_mac_count); | 637 | pkt_dev->src_mac_count, pkt_dev->dst_mac_count); |
628 | 638 | ||
639 | if (pkt_dev->nr_labels) { | ||
640 | unsigned i; | ||
641 | seq_printf(seq, " mpls: "); | ||
642 | for(i = 0; i < pkt_dev->nr_labels; i++) | ||
643 | seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), | ||
644 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); | ||
645 | } | ||
646 | |||
647 | seq_printf(seq, " Flags: "); | ||
648 | |||
629 | if (pkt_dev->flags & F_IPV6) | 649 | if (pkt_dev->flags & F_IPV6) |
630 | seq_printf(seq, "IPV6 "); | 650 | seq_printf(seq, "IPV6 "); |
631 | 651 | ||
@@ -644,6 +664,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
644 | if (pkt_dev->flags & F_UDPDST_RND) | 664 | if (pkt_dev->flags & F_UDPDST_RND) |
645 | seq_printf(seq, "UDPDST_RND "); | 665 | seq_printf(seq, "UDPDST_RND "); |
646 | 666 | ||
667 | if (pkt_dev->flags & F_MPLS_RND) | ||
668 | seq_printf(seq, "MPLS_RND "); | ||
669 | |||
647 | if (pkt_dev->flags & F_MACSRC_RND) | 670 | if (pkt_dev->flags & F_MACSRC_RND) |
648 | seq_printf(seq, "MACSRC_RND "); | 671 | seq_printf(seq, "MACSRC_RND "); |
649 | 672 | ||
@@ -691,6 +714,29 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
691 | return 0; | 714 | return 0; |
692 | } | 715 | } |
693 | 716 | ||
717 | |||
718 | static int hex32_arg(const char __user *user_buffer, __u32 *num) | ||
719 | { | ||
720 | int i = 0; | ||
721 | *num = 0; | ||
722 | |||
723 | for(; i < 8; i++) { | ||
724 | char c; | ||
725 | *num <<= 4; | ||
726 | if (get_user(c, &user_buffer[i])) | ||
727 | return -EFAULT; | ||
728 | if ((c >= '0') && (c <= '9')) | ||
729 | *num |= c - '0'; | ||
730 | else if ((c >= 'a') && (c <= 'f')) | ||
731 | *num |= c - 'a' + 10; | ||
732 | else if ((c >= 'A') && (c <= 'F')) | ||
733 | *num |= c - 'A' + 10; | ||
734 | else | ||
735 | break; | ||
736 | } | ||
737 | return i; | ||
738 | } | ||
739 | |||
694 | static int count_trail_chars(const char __user * user_buffer, | 740 | static int count_trail_chars(const char __user * user_buffer, |
695 | unsigned int maxlen) | 741 | unsigned int maxlen) |
696 | { | 742 | { |
@@ -759,6 +805,35 @@ done_str: | |||
759 | return i; | 805 | return i; |
760 | } | 806 | } |
761 | 807 | ||
808 | static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) | ||
809 | { | ||
810 | unsigned n = 0; | ||
811 | char c; | ||
812 | ssize_t i = 0; | ||
813 | int len; | ||
814 | |||
815 | pkt_dev->nr_labels = 0; | ||
816 | do { | ||
817 | __u32 tmp; | ||
818 | len = hex32_arg(&buffer[i], &tmp); | ||
819 | if (len <= 0) | ||
820 | return len; | ||
821 | pkt_dev->labels[n] = htonl(tmp); | ||
822 | if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) | ||
823 | pkt_dev->flags |= F_MPLS_RND; | ||
824 | i += len; | ||
825 | if (get_user(c, &buffer[i])) | ||
826 | return -EFAULT; | ||
827 | i++; | ||
828 | n++; | ||
829 | if (n >= MAX_MPLS_LABELS) | ||
830 | return -E2BIG; | ||
831 | } while(c == ','); | ||
832 | |||
833 | pkt_dev->nr_labels = n; | ||
834 | return i; | ||
835 | } | ||
836 | |||
762 | static ssize_t pktgen_if_write(struct file *file, | 837 | static ssize_t pktgen_if_write(struct file *file, |
763 | const char __user * user_buffer, size_t count, | 838 | const char __user * user_buffer, size_t count, |
764 | loff_t * offset) | 839 | loff_t * offset) |
@@ -1059,6 +1134,12 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1059 | else if (strcmp(f, "!MACDST_RND") == 0) | 1134 | else if (strcmp(f, "!MACDST_RND") == 0) |
1060 | pkt_dev->flags &= ~F_MACDST_RND; | 1135 | pkt_dev->flags &= ~F_MACDST_RND; |
1061 | 1136 | ||
1137 | else if (strcmp(f, "MPLS_RND") == 0) | ||
1138 | pkt_dev->flags |= F_MPLS_RND; | ||
1139 | |||
1140 | else if (strcmp(f, "!MPLS_RND") == 0) | ||
1141 | pkt_dev->flags &= ~F_MPLS_RND; | ||
1142 | |||
1062 | else { | 1143 | else { |
1063 | sprintf(pg_result, | 1144 | sprintf(pg_result, |
1064 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | 1145 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", |
@@ -1354,6 +1435,19 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1354 | return count; | 1435 | return count; |
1355 | } | 1436 | } |
1356 | 1437 | ||
1438 | if (!strcmp(name, "mpls")) { | ||
1439 | unsigned n, offset; | ||
1440 | len = get_labels(&user_buffer[i], pkt_dev); | ||
1441 | if (len < 0) { return len; } | ||
1442 | i += len; | ||
1443 | offset = sprintf(pg_result, "OK: mpls="); | ||
1444 | for(n = 0; n < pkt_dev->nr_labels; n++) | ||
1445 | offset += sprintf(pg_result + offset, | ||
1446 | "%08x%s", ntohl(pkt_dev->labels[n]), | ||
1447 | n == pkt_dev->nr_labels-1 ? "" : ","); | ||
1448 | return count; | ||
1449 | } | ||
1450 | |||
1357 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); | 1451 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); |
1358 | return -EINVAL; | 1452 | return -EINVAL; |
1359 | } | 1453 | } |
@@ -1846,6 +1940,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
1846 | pkt_dev->hh[1] = tmp; | 1940 | pkt_dev->hh[1] = tmp; |
1847 | } | 1941 | } |
1848 | 1942 | ||
1943 | if (pkt_dev->flags & F_MPLS_RND) { | ||
1944 | unsigned i; | ||
1945 | for(i = 0; i < pkt_dev->nr_labels; i++) | ||
1946 | if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) | ||
1947 | pkt_dev->labels[i] = MPLS_STACK_BOTTOM | | ||
1948 | (pktgen_random() & | ||
1949 | htonl(0x000fffff)); | ||
1950 | } | ||
1951 | |||
1849 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { | 1952 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { |
1850 | if (pkt_dev->flags & F_UDPSRC_RND) | 1953 | if (pkt_dev->flags & F_UDPSRC_RND) |
1851 | pkt_dev->cur_udp_src = | 1954 | pkt_dev->cur_udp_src = |
@@ -1968,6 +2071,16 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
1968 | pkt_dev->flows[flow].count++; | 2071 | pkt_dev->flows[flow].count++; |
1969 | } | 2072 | } |
1970 | 2073 | ||
2074 | static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) | ||
2075 | { | ||
2076 | unsigned i; | ||
2077 | for(i = 0; i < pkt_dev->nr_labels; i++) { | ||
2078 | *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; | ||
2079 | } | ||
2080 | mpls--; | ||
2081 | *mpls |= MPLS_STACK_BOTTOM; | ||
2082 | } | ||
2083 | |||
1971 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | 2084 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, |
1972 | struct pktgen_dev *pkt_dev) | 2085 | struct pktgen_dev *pkt_dev) |
1973 | { | 2086 | { |
@@ -1977,6 +2090,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1977 | int datalen, iplen; | 2090 | int datalen, iplen; |
1978 | struct iphdr *iph; | 2091 | struct iphdr *iph; |
1979 | struct pktgen_hdr *pgh = NULL; | 2092 | struct pktgen_hdr *pgh = NULL; |
2093 | __be16 protocol = __constant_htons(ETH_P_IP); | ||
2094 | __be32 *mpls; | ||
2095 | |||
2096 | if (pkt_dev->nr_labels) | ||
2097 | protocol = __constant_htons(ETH_P_MPLS_UC); | ||
1980 | 2098 | ||
1981 | /* Update any of the values, used when we're incrementing various | 2099 | /* Update any of the values, used when we're incrementing various |
1982 | * fields. | 2100 | * fields. |
@@ -1984,7 +2102,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1984 | mod_cur_headers(pkt_dev); | 2102 | mod_cur_headers(pkt_dev); |
1985 | 2103 | ||
1986 | datalen = (odev->hard_header_len + 16) & ~0xf; | 2104 | datalen = (odev->hard_header_len + 16) & ~0xf; |
1987 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen, GFP_ATOMIC); | 2105 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + |
2106 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | ||
1988 | if (!skb) { | 2107 | if (!skb) { |
1989 | sprintf(pkt_dev->result, "No memory"); | 2108 | sprintf(pkt_dev->result, "No memory"); |
1990 | return NULL; | 2109 | return NULL; |
@@ -1994,13 +2113,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1994 | 2113 | ||
1995 | /* Reserve for ethernet and IP header */ | 2114 | /* Reserve for ethernet and IP header */ |
1996 | eth = (__u8 *) skb_push(skb, 14); | 2115 | eth = (__u8 *) skb_push(skb, 14); |
2116 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | ||
2117 | if (pkt_dev->nr_labels) | ||
2118 | mpls_push(mpls, pkt_dev); | ||
1997 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); | 2119 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); |
1998 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2120 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
1999 | 2121 | ||
2000 | memcpy(eth, pkt_dev->hh, 12); | 2122 | memcpy(eth, pkt_dev->hh, 12); |
2001 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IP); | 2123 | *(u16 *) & eth[12] = protocol; |
2002 | 2124 | ||
2003 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ | 2125 | /* Eth + IPh + UDPh + mpls */ |
2126 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - | ||
2127 | pkt_dev->nr_labels*sizeof(u32); | ||
2004 | if (datalen < sizeof(struct pktgen_hdr)) | 2128 | if (datalen < sizeof(struct pktgen_hdr)) |
2005 | datalen = sizeof(struct pktgen_hdr); | 2129 | datalen = sizeof(struct pktgen_hdr); |
2006 | 2130 | ||
@@ -2021,8 +2145,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2021 | iph->tot_len = htons(iplen); | 2145 | iph->tot_len = htons(iplen); |
2022 | iph->check = 0; | 2146 | iph->check = 0; |
2023 | iph->check = ip_fast_csum((void *)iph, iph->ihl); | 2147 | iph->check = ip_fast_csum((void *)iph, iph->ihl); |
2024 | skb->protocol = __constant_htons(ETH_P_IP); | 2148 | skb->protocol = protocol; |
2025 | skb->mac.raw = ((u8 *) iph) - 14; | 2149 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); |
2026 | skb->dev = odev; | 2150 | skb->dev = odev; |
2027 | skb->pkt_type = PACKET_HOST; | 2151 | skb->pkt_type = PACKET_HOST; |
2028 | 2152 | ||
@@ -2274,13 +2398,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2274 | int datalen; | 2398 | int datalen; |
2275 | struct ipv6hdr *iph; | 2399 | struct ipv6hdr *iph; |
2276 | struct pktgen_hdr *pgh = NULL; | 2400 | struct pktgen_hdr *pgh = NULL; |
2401 | __be16 protocol = __constant_htons(ETH_P_IPV6); | ||
2402 | __be32 *mpls; | ||
2403 | |||
2404 | if (pkt_dev->nr_labels) | ||
2405 | protocol = __constant_htons(ETH_P_MPLS_UC); | ||
2277 | 2406 | ||
2278 | /* Update any of the values, used when we're incrementing various | 2407 | /* Update any of the values, used when we're incrementing various |
2279 | * fields. | 2408 | * fields. |
2280 | */ | 2409 | */ |
2281 | mod_cur_headers(pkt_dev); | 2410 | mod_cur_headers(pkt_dev); |
2282 | 2411 | ||
2283 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC); | 2412 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + |
2413 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | ||
2284 | if (!skb) { | 2414 | if (!skb) { |
2285 | sprintf(pkt_dev->result, "No memory"); | 2415 | sprintf(pkt_dev->result, "No memory"); |
2286 | return NULL; | 2416 | return NULL; |
@@ -2290,13 +2420,19 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2290 | 2420 | ||
2291 | /* Reserve for ethernet and IP header */ | 2421 | /* Reserve for ethernet and IP header */ |
2292 | eth = (__u8 *) skb_push(skb, 14); | 2422 | eth = (__u8 *) skb_push(skb, 14); |
2423 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | ||
2424 | if (pkt_dev->nr_labels) | ||
2425 | mpls_push(mpls, pkt_dev); | ||
2293 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); | 2426 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); |
2294 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2427 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
2295 | 2428 | ||
2296 | memcpy(eth, pkt_dev->hh, 12); | 2429 | memcpy(eth, pkt_dev->hh, 12); |
2297 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); | 2430 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); |
2298 | 2431 | ||
2299 | datalen = pkt_dev->cur_pkt_size - 14 - sizeof(struct ipv6hdr) - sizeof(struct udphdr); /* Eth + IPh + UDPh */ | 2432 | /* Eth + IPh + UDPh + mpls */ |
2433 | datalen = pkt_dev->cur_pkt_size - 14 - | ||
2434 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - | ||
2435 | pkt_dev->nr_labels*sizeof(u32); | ||
2300 | 2436 | ||
2301 | if (datalen < sizeof(struct pktgen_hdr)) { | 2437 | if (datalen < sizeof(struct pktgen_hdr)) { |
2302 | datalen = sizeof(struct pktgen_hdr); | 2438 | datalen = sizeof(struct pktgen_hdr); |
@@ -2320,8 +2456,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2320 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); | 2456 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); |
2321 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); | 2457 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); |
2322 | 2458 | ||
2323 | skb->mac.raw = ((u8 *) iph) - 14; | 2459 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); |
2324 | skb->protocol = __constant_htons(ETH_P_IPV6); | 2460 | skb->protocol = protocol; |
2325 | skb->dev = odev; | 2461 | skb->dev = odev; |
2326 | skb->pkt_type = PACKET_HOST; | 2462 | skb->pkt_type = PACKET_HOST; |
2327 | 2463 | ||