diff options
| -rw-r--r-- | Documentation/networking/pktgen.txt | 20 | ||||
| -rw-r--r-- | net/core/pktgen.c | 158 |
2 files changed, 166 insertions, 12 deletions
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt index cc4b4d04129c..278771c9ad99 100644 --- a/Documentation/networking/pktgen.txt +++ b/Documentation/networking/pktgen.txt | |||
| @@ -109,6 +109,22 @@ Examples: | |||
| 109 | cycle through the port range. | 109 | cycle through the port range. |
| 110 | pgset "udp_dst_max 9" set UDP destination port max. | 110 | pgset "udp_dst_max 9" set UDP destination port max. |
| 111 | 111 | ||
| 112 | pgset "mpls 0001000a,0002000a,0000000a" set MPLS labels (in this example | ||
| 113 | outer label=16,middle label=32, | ||
| 114 | inner label=0 (IPv4 NULL)) Note that | ||
| 115 | there must be no spaces between the | ||
| 116 | arguments. Leading zeros are required. | ||
| 117 | Do not set the bottom of stack bit, | ||
| 118 | thats done automatically. If you do | ||
| 119 | set the bottom of stack bit, that | ||
| 120 | indicates that you want to randomly | ||
| 121 | generate that address and the flag | ||
| 122 | MPLS_RND will be turned on. You | ||
| 123 | can have any mix of random and fixed | ||
| 124 | labels in the label stack. | ||
| 125 | |||
| 126 | pgset "mpls 0" turn off mpls (or any invalid argument works too!) | ||
| 127 | |||
| 112 | pgset stop aborts injection. Also, ^C aborts generator. | 128 | pgset stop aborts injection. Also, ^C aborts generator. |
| 113 | 129 | ||
| 114 | 130 | ||
| @@ -167,6 +183,8 @@ pkt_size | |||
| 167 | min_pkt_size | 183 | min_pkt_size |
| 168 | max_pkt_size | 184 | max_pkt_size |
| 169 | 185 | ||
| 186 | mpls | ||
| 187 | |||
| 170 | udp_src_min | 188 | udp_src_min |
| 171 | udp_src_max | 189 | udp_src_max |
| 172 | 190 | ||
| @@ -211,4 +229,4 @@ Grant Grundler for testing on IA-64 and parisc, Harald Welte, Lennert Buytenhek | |||
| 211 | Stephen Hemminger, Andi Kleen, Dave Miller and many others. | 229 | Stephen Hemminger, Andi Kleen, Dave Miller and many others. |
| 212 | 230 | ||
| 213 | 231 | ||
| 214 | Good luck with the linux net-development. \ No newline at end of file | 232 | Good luck with the linux net-development. |
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 | ||
