diff options
author | Francesco Fondelli <francesco.fondelli@gmail.com> | 2006-09-27 19:30:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-28 21:01:46 -0400 |
commit | 34954ddc4f3e790fb6d5ed331513f54b38713234 (patch) | |
tree | d0bdd9f7b3a5240cb65a5944ad1ba94e3317016c /net | |
parent | 658270a0a49612a0e3fdc01c2e8c0e1a6d47cbf4 (diff) |
[PKTGEN]: vlan support
The attached patch allows pktgen to produce 802.1Q and Q-in-Q tagged frames.
I have used it for stress test a bridge and seems ok to me.
Unfortunately I have no access to net-2.6.x git tree so the diff is against
2.6.17.13.
Signed-off-by: Francesco Fondelli <francesco.fondelli@gmail.com>
Acked-by: Steven Whitehouse <steve@chygwyn.com>
Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/pktgen.c | 256 |
1 files changed, 247 insertions, 9 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 72145d4a2600..033802769e4f 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -109,6 +109,8 @@ | |||
109 | * | 109 | * |
110 | * MPLS support by Steven Whitehouse <steve@chygwyn.com> | 110 | * MPLS support by Steven Whitehouse <steve@chygwyn.com> |
111 | * | 111 | * |
112 | * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> | ||
113 | * | ||
112 | */ | 114 | */ |
113 | #include <linux/sys.h> | 115 | #include <linux/sys.h> |
114 | #include <linux/types.h> | 116 | #include <linux/types.h> |
@@ -137,6 +139,7 @@ | |||
137 | #include <linux/inetdevice.h> | 139 | #include <linux/inetdevice.h> |
138 | #include <linux/rtnetlink.h> | 140 | #include <linux/rtnetlink.h> |
139 | #include <linux/if_arp.h> | 141 | #include <linux/if_arp.h> |
142 | #include <linux/if_vlan.h> | ||
140 | #include <linux/in.h> | 143 | #include <linux/in.h> |
141 | #include <linux/ip.h> | 144 | #include <linux/ip.h> |
142 | #include <linux/ipv6.h> | 145 | #include <linux/ipv6.h> |
@@ -178,6 +181,8 @@ | |||
178 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ | 181 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ |
179 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ | 182 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ |
180 | #define F_MPLS_RND (1<<8) /* Random MPLS labels */ | 183 | #define F_MPLS_RND (1<<8) /* Random MPLS labels */ |
184 | #define F_VID_RND (1<<9) /* Random VLAN ID */ | ||
185 | #define F_SVID_RND (1<<10) /* Random SVLAN ID */ | ||
181 | 186 | ||
182 | /* Thread control flag bits */ | 187 | /* Thread control flag bits */ |
183 | #define T_TERMINATE (1<<0) | 188 | #define T_TERMINATE (1<<0) |
@@ -198,6 +203,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL; | |||
198 | 203 | ||
199 | #define MAX_CFLOWS 65536 | 204 | #define MAX_CFLOWS 65536 |
200 | 205 | ||
206 | #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) | ||
207 | #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) | ||
208 | |||
201 | struct flow_state { | 209 | struct flow_state { |
202 | __u32 cur_daddr; | 210 | __u32 cur_daddr; |
203 | int count; | 211 | int count; |
@@ -288,6 +296,15 @@ struct pktgen_dev { | |||
288 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ | 296 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ |
289 | __be32 labels[MAX_MPLS_LABELS]; | 297 | __be32 labels[MAX_MPLS_LABELS]; |
290 | 298 | ||
299 | /* VLAN/SVLAN (802.1Q/Q-in-Q) */ | ||
300 | __u8 vlan_p; | ||
301 | __u8 vlan_cfi; | ||
302 | __u16 vlan_id; /* 0xffff means no vlan tag */ | ||
303 | |||
304 | __u8 svlan_p; | ||
305 | __u8 svlan_cfi; | ||
306 | __u16 svlan_id; /* 0xffff means no svlan tag */ | ||
307 | |||
291 | __u32 src_mac_count; /* How many MACs to iterate through */ | 308 | __u32 src_mac_count; /* How many MACs to iterate through */ |
292 | __u32 dst_mac_count; /* How many MACs to iterate through */ | 309 | __u32 dst_mac_count; /* How many MACs to iterate through */ |
293 | 310 | ||
@@ -644,6 +661,16 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
644 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); | 661 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); |
645 | } | 662 | } |
646 | 663 | ||
664 | if (pkt_dev->vlan_id != 0xffff) { | ||
665 | seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", | ||
666 | pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi); | ||
667 | } | ||
668 | |||
669 | if (pkt_dev->svlan_id != 0xffff) { | ||
670 | seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", | ||
671 | pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi); | ||
672 | } | ||
673 | |||
647 | seq_printf(seq, " Flags: "); | 674 | seq_printf(seq, " Flags: "); |
648 | 675 | ||
649 | if (pkt_dev->flags & F_IPV6) | 676 | if (pkt_dev->flags & F_IPV6) |
@@ -673,6 +700,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
673 | if (pkt_dev->flags & F_MACDST_RND) | 700 | if (pkt_dev->flags & F_MACDST_RND) |
674 | seq_printf(seq, "MACDST_RND "); | 701 | seq_printf(seq, "MACDST_RND "); |
675 | 702 | ||
703 | if (pkt_dev->flags & F_VID_RND) | ||
704 | seq_printf(seq, "VID_RND "); | ||
705 | |||
706 | if (pkt_dev->flags & F_SVID_RND) | ||
707 | seq_printf(seq, "SVID_RND "); | ||
708 | |||
676 | seq_puts(seq, "\n"); | 709 | seq_puts(seq, "\n"); |
677 | 710 | ||
678 | sa = pkt_dev->started_at; | 711 | sa = pkt_dev->started_at; |
@@ -1140,6 +1173,18 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1140 | else if (strcmp(f, "!MPLS_RND") == 0) | 1173 | else if (strcmp(f, "!MPLS_RND") == 0) |
1141 | pkt_dev->flags &= ~F_MPLS_RND; | 1174 | pkt_dev->flags &= ~F_MPLS_RND; |
1142 | 1175 | ||
1176 | else if (strcmp(f, "VID_RND") == 0) | ||
1177 | pkt_dev->flags |= F_VID_RND; | ||
1178 | |||
1179 | else if (strcmp(f, "!VID_RND") == 0) | ||
1180 | pkt_dev->flags &= ~F_VID_RND; | ||
1181 | |||
1182 | else if (strcmp(f, "SVID_RND") == 0) | ||
1183 | pkt_dev->flags |= F_SVID_RND; | ||
1184 | |||
1185 | else if (strcmp(f, "!SVID_RND") == 0) | ||
1186 | pkt_dev->flags &= ~F_SVID_RND; | ||
1187 | |||
1143 | else { | 1188 | else { |
1144 | sprintf(pg_result, | 1189 | sprintf(pg_result, |
1145 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | 1190 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", |
@@ -1445,6 +1490,128 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1445 | offset += sprintf(pg_result + offset, | 1490 | offset += sprintf(pg_result + offset, |
1446 | "%08x%s", ntohl(pkt_dev->labels[n]), | 1491 | "%08x%s", ntohl(pkt_dev->labels[n]), |
1447 | n == pkt_dev->nr_labels-1 ? "" : ","); | 1492 | n == pkt_dev->nr_labels-1 ? "" : ","); |
1493 | |||
1494 | if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { | ||
1495 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
1496 | pkt_dev->svlan_id = 0xffff; | ||
1497 | |||
1498 | if (debug) | ||
1499 | printk("pktgen: VLAN/SVLAN auto turned off\n"); | ||
1500 | } | ||
1501 | return count; | ||
1502 | } | ||
1503 | |||
1504 | if (!strcmp(name, "vlan_id")) { | ||
1505 | len = num_arg(&user_buffer[i], 4, &value); | ||
1506 | if (len < 0) { | ||
1507 | return len; | ||
1508 | } | ||
1509 | i += len; | ||
1510 | if (value <= 4095) { | ||
1511 | pkt_dev->vlan_id = value; /* turn on VLAN */ | ||
1512 | |||
1513 | if (debug) | ||
1514 | printk("pktgen: VLAN turned on\n"); | ||
1515 | |||
1516 | if (debug && pkt_dev->nr_labels) | ||
1517 | printk("pktgen: MPLS auto turned off\n"); | ||
1518 | |||
1519 | pkt_dev->nr_labels = 0; /* turn off MPLS */ | ||
1520 | sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); | ||
1521 | } else { | ||
1522 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
1523 | pkt_dev->svlan_id = 0xffff; | ||
1524 | |||
1525 | if (debug) | ||
1526 | printk("pktgen: VLAN/SVLAN turned off\n"); | ||
1527 | } | ||
1528 | return count; | ||
1529 | } | ||
1530 | |||
1531 | if (!strcmp(name, "vlan_p")) { | ||
1532 | len = num_arg(&user_buffer[i], 1, &value); | ||
1533 | if (len < 0) { | ||
1534 | return len; | ||
1535 | } | ||
1536 | i += len; | ||
1537 | if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { | ||
1538 | pkt_dev->vlan_p = value; | ||
1539 | sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); | ||
1540 | } else { | ||
1541 | sprintf(pg_result, "ERROR: vlan_p must be 0-7"); | ||
1542 | } | ||
1543 | return count; | ||
1544 | } | ||
1545 | |||
1546 | if (!strcmp(name, "vlan_cfi")) { | ||
1547 | len = num_arg(&user_buffer[i], 1, &value); | ||
1548 | if (len < 0) { | ||
1549 | return len; | ||
1550 | } | ||
1551 | i += len; | ||
1552 | if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { | ||
1553 | pkt_dev->vlan_cfi = value; | ||
1554 | sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); | ||
1555 | } else { | ||
1556 | sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); | ||
1557 | } | ||
1558 | return count; | ||
1559 | } | ||
1560 | |||
1561 | if (!strcmp(name, "svlan_id")) { | ||
1562 | len = num_arg(&user_buffer[i], 4, &value); | ||
1563 | if (len < 0) { | ||
1564 | return len; | ||
1565 | } | ||
1566 | i += len; | ||
1567 | if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { | ||
1568 | pkt_dev->svlan_id = value; /* turn on SVLAN */ | ||
1569 | |||
1570 | if (debug) | ||
1571 | printk("pktgen: SVLAN turned on\n"); | ||
1572 | |||
1573 | if (debug && pkt_dev->nr_labels) | ||
1574 | printk("pktgen: MPLS auto turned off\n"); | ||
1575 | |||
1576 | pkt_dev->nr_labels = 0; /* turn off MPLS */ | ||
1577 | sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); | ||
1578 | } else { | ||
1579 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
1580 | pkt_dev->svlan_id = 0xffff; | ||
1581 | |||
1582 | if (debug) | ||
1583 | printk("pktgen: VLAN/SVLAN turned off\n"); | ||
1584 | } | ||
1585 | return count; | ||
1586 | } | ||
1587 | |||
1588 | if (!strcmp(name, "svlan_p")) { | ||
1589 | len = num_arg(&user_buffer[i], 1, &value); | ||
1590 | if (len < 0) { | ||
1591 | return len; | ||
1592 | } | ||
1593 | i += len; | ||
1594 | if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { | ||
1595 | pkt_dev->svlan_p = value; | ||
1596 | sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); | ||
1597 | } else { | ||
1598 | sprintf(pg_result, "ERROR: svlan_p must be 0-7"); | ||
1599 | } | ||
1600 | return count; | ||
1601 | } | ||
1602 | |||
1603 | if (!strcmp(name, "svlan_cfi")) { | ||
1604 | len = num_arg(&user_buffer[i], 1, &value); | ||
1605 | if (len < 0) { | ||
1606 | return len; | ||
1607 | } | ||
1608 | i += len; | ||
1609 | if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { | ||
1610 | pkt_dev->svlan_cfi = value; | ||
1611 | sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); | ||
1612 | } else { | ||
1613 | sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); | ||
1614 | } | ||
1448 | return count; | 1615 | return count; |
1449 | } | 1616 | } |
1450 | 1617 | ||
@@ -1949,6 +2116,14 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
1949 | htonl(0x000fffff)); | 2116 | htonl(0x000fffff)); |
1950 | } | 2117 | } |
1951 | 2118 | ||
2119 | if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { | ||
2120 | pkt_dev->vlan_id = pktgen_random() % 4096; | ||
2121 | } | ||
2122 | |||
2123 | if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { | ||
2124 | pkt_dev->svlan_id = pktgen_random() % 4096; | ||
2125 | } | ||
2126 | |||
1952 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { | 2127 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { |
1953 | if (pkt_dev->flags & F_UDPSRC_RND) | 2128 | if (pkt_dev->flags & F_UDPSRC_RND) |
1954 | pkt_dev->cur_udp_src = | 2129 | pkt_dev->cur_udp_src = |
@@ -2092,10 +2267,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2092 | struct pktgen_hdr *pgh = NULL; | 2267 | struct pktgen_hdr *pgh = NULL; |
2093 | __be16 protocol = __constant_htons(ETH_P_IP); | 2268 | __be16 protocol = __constant_htons(ETH_P_IP); |
2094 | __be32 *mpls; | 2269 | __be32 *mpls; |
2270 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | ||
2271 | __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ | ||
2272 | __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ | ||
2273 | __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ | ||
2274 | |||
2095 | 2275 | ||
2096 | if (pkt_dev->nr_labels) | 2276 | if (pkt_dev->nr_labels) |
2097 | protocol = __constant_htons(ETH_P_MPLS_UC); | 2277 | protocol = __constant_htons(ETH_P_MPLS_UC); |
2098 | 2278 | ||
2279 | if (pkt_dev->vlan_id != 0xffff) | ||
2280 | protocol = __constant_htons(ETH_P_8021Q); | ||
2281 | |||
2099 | /* Update any of the values, used when we're incrementing various | 2282 | /* Update any of the values, used when we're incrementing various |
2100 | * fields. | 2283 | * fields. |
2101 | */ | 2284 | */ |
@@ -2103,7 +2286,9 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2103 | 2286 | ||
2104 | datalen = (odev->hard_header_len + 16) & ~0xf; | 2287 | datalen = (odev->hard_header_len + 16) & ~0xf; |
2105 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + | 2288 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + |
2106 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | 2289 | pkt_dev->nr_labels*sizeof(u32) + |
2290 | VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev), | ||
2291 | GFP_ATOMIC); | ||
2107 | if (!skb) { | 2292 | if (!skb) { |
2108 | sprintf(pkt_dev->result, "No memory"); | 2293 | sprintf(pkt_dev->result, "No memory"); |
2109 | return NULL; | 2294 | return NULL; |
@@ -2116,6 +2301,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2116 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | 2301 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); |
2117 | if (pkt_dev->nr_labels) | 2302 | if (pkt_dev->nr_labels) |
2118 | mpls_push(mpls, pkt_dev); | 2303 | mpls_push(mpls, pkt_dev); |
2304 | |||
2305 | if (pkt_dev->vlan_id != 0xffff) { | ||
2306 | if(pkt_dev->svlan_id != 0xffff) { | ||
2307 | svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2308 | *svlan_tci = htons(pkt_dev->svlan_id); | ||
2309 | *svlan_tci |= pkt_dev->svlan_p << 5; | ||
2310 | *svlan_tci |= pkt_dev->svlan_cfi << 4; | ||
2311 | svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2312 | *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q); | ||
2313 | } | ||
2314 | vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2315 | *vlan_tci = htons(pkt_dev->vlan_id); | ||
2316 | *vlan_tci |= pkt_dev->vlan_p << 5; | ||
2317 | *vlan_tci |= pkt_dev->vlan_cfi << 4; | ||
2318 | vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2319 | *vlan_encapsulated_proto = __constant_htons(ETH_P_IP); | ||
2320 | } | ||
2321 | |||
2119 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); | 2322 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); |
2120 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2323 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
2121 | 2324 | ||
@@ -2124,7 +2327,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2124 | 2327 | ||
2125 | /* Eth + IPh + UDPh + mpls */ | 2328 | /* Eth + IPh + UDPh + mpls */ |
2126 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - | 2329 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - |
2127 | pkt_dev->nr_labels*sizeof(u32); | 2330 | pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); |
2128 | if (datalen < sizeof(struct pktgen_hdr)) | 2331 | if (datalen < sizeof(struct pktgen_hdr)) |
2129 | datalen = sizeof(struct pktgen_hdr); | 2332 | datalen = sizeof(struct pktgen_hdr); |
2130 | 2333 | ||
@@ -2146,7 +2349,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2146 | iph->check = 0; | 2349 | iph->check = 0; |
2147 | iph->check = ip_fast_csum((void *)iph, iph->ihl); | 2350 | iph->check = ip_fast_csum((void *)iph, iph->ihl); |
2148 | skb->protocol = protocol; | 2351 | skb->protocol = protocol; |
2149 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); | 2352 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) - |
2353 | VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); | ||
2150 | skb->dev = odev; | 2354 | skb->dev = odev; |
2151 | skb->pkt_type = PACKET_HOST; | 2355 | skb->pkt_type = PACKET_HOST; |
2152 | skb->nh.iph = iph; | 2356 | skb->nh.iph = iph; |
@@ -2218,7 +2422,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2218 | pgh->tv_sec = htonl(timestamp.tv_sec); | 2422 | pgh->tv_sec = htonl(timestamp.tv_sec); |
2219 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2423 | pgh->tv_usec = htonl(timestamp.tv_usec); |
2220 | } | 2424 | } |
2221 | pkt_dev->seq_num++; | ||
2222 | 2425 | ||
2223 | return skb; | 2426 | return skb; |
2224 | } | 2427 | } |
@@ -2402,17 +2605,26 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2402 | struct pktgen_hdr *pgh = NULL; | 2605 | struct pktgen_hdr *pgh = NULL; |
2403 | __be16 protocol = __constant_htons(ETH_P_IPV6); | 2606 | __be16 protocol = __constant_htons(ETH_P_IPV6); |
2404 | __be32 *mpls; | 2607 | __be32 *mpls; |
2608 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | ||
2609 | __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ | ||
2610 | __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ | ||
2611 | __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ | ||
2405 | 2612 | ||
2406 | if (pkt_dev->nr_labels) | 2613 | if (pkt_dev->nr_labels) |
2407 | protocol = __constant_htons(ETH_P_MPLS_UC); | 2614 | protocol = __constant_htons(ETH_P_MPLS_UC); |
2408 | 2615 | ||
2616 | if (pkt_dev->vlan_id != 0xffff) | ||
2617 | protocol = __constant_htons(ETH_P_8021Q); | ||
2618 | |||
2409 | /* Update any of the values, used when we're incrementing various | 2619 | /* Update any of the values, used when we're incrementing various |
2410 | * fields. | 2620 | * fields. |
2411 | */ | 2621 | */ |
2412 | mod_cur_headers(pkt_dev); | 2622 | mod_cur_headers(pkt_dev); |
2413 | 2623 | ||
2414 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + | 2624 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + |
2415 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | 2625 | pkt_dev->nr_labels*sizeof(u32) + |
2626 | VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev), | ||
2627 | GFP_ATOMIC); | ||
2416 | if (!skb) { | 2628 | if (!skb) { |
2417 | sprintf(pkt_dev->result, "No memory"); | 2629 | sprintf(pkt_dev->result, "No memory"); |
2418 | return NULL; | 2630 | return NULL; |
@@ -2425,16 +2637,34 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2425 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | 2637 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); |
2426 | if (pkt_dev->nr_labels) | 2638 | if (pkt_dev->nr_labels) |
2427 | mpls_push(mpls, pkt_dev); | 2639 | mpls_push(mpls, pkt_dev); |
2640 | |||
2641 | if (pkt_dev->vlan_id != 0xffff) { | ||
2642 | if(pkt_dev->svlan_id != 0xffff) { | ||
2643 | svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2644 | *svlan_tci = htons(pkt_dev->svlan_id); | ||
2645 | *svlan_tci |= pkt_dev->svlan_p << 5; | ||
2646 | *svlan_tci |= pkt_dev->svlan_cfi << 4; | ||
2647 | svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2648 | *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q); | ||
2649 | } | ||
2650 | vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2651 | *vlan_tci = htons(pkt_dev->vlan_id); | ||
2652 | *vlan_tci |= pkt_dev->vlan_p << 5; | ||
2653 | *vlan_tci |= pkt_dev->vlan_cfi << 4; | ||
2654 | vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
2655 | *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6); | ||
2656 | } | ||
2657 | |||
2428 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); | 2658 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); |
2429 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2659 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
2430 | 2660 | ||
2431 | memcpy(eth, pkt_dev->hh, 12); | 2661 | memcpy(eth, pkt_dev->hh, 12); |
2432 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); | 2662 | *(u16 *) & eth[12] = protocol; |
2433 | 2663 | ||
2434 | /* Eth + IPh + UDPh + mpls */ | 2664 | /* Eth + IPh + UDPh + mpls */ |
2435 | datalen = pkt_dev->cur_pkt_size - 14 - | 2665 | datalen = pkt_dev->cur_pkt_size - 14 - |
2436 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - | 2666 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - |
2437 | pkt_dev->nr_labels*sizeof(u32); | 2667 | pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); |
2438 | 2668 | ||
2439 | if (datalen < sizeof(struct pktgen_hdr)) { | 2669 | if (datalen < sizeof(struct pktgen_hdr)) { |
2440 | datalen = sizeof(struct pktgen_hdr); | 2670 | datalen = sizeof(struct pktgen_hdr); |
@@ -2458,7 +2688,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2458 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); | 2688 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); |
2459 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); | 2689 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); |
2460 | 2690 | ||
2461 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); | 2691 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) - |
2692 | VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); | ||
2462 | skb->protocol = protocol; | 2693 | skb->protocol = protocol; |
2463 | skb->dev = odev; | 2694 | skb->dev = odev; |
2464 | skb->pkt_type = PACKET_HOST; | 2695 | skb->pkt_type = PACKET_HOST; |
@@ -2531,7 +2762,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2531 | pgh->tv_sec = htonl(timestamp.tv_sec); | 2762 | pgh->tv_sec = htonl(timestamp.tv_sec); |
2532 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2763 | pgh->tv_usec = htonl(timestamp.tv_usec); |
2533 | } | 2764 | } |
2534 | pkt_dev->seq_num++; | 2765 | /* pkt_dev->seq_num++; FF: you really mean this? */ |
2535 | 2766 | ||
2536 | return skb; | 2767 | return skb; |
2537 | } | 2768 | } |
@@ -3177,6 +3408,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3177 | pkt_dev->udp_dst_min = 9; | 3408 | pkt_dev->udp_dst_min = 9; |
3178 | pkt_dev->udp_dst_max = 9; | 3409 | pkt_dev->udp_dst_max = 9; |
3179 | 3410 | ||
3411 | pkt_dev->vlan_p = 0; | ||
3412 | pkt_dev->vlan_cfi = 0; | ||
3413 | pkt_dev->vlan_id = 0xffff; | ||
3414 | pkt_dev->svlan_p = 0; | ||
3415 | pkt_dev->svlan_cfi = 0; | ||
3416 | pkt_dev->svlan_id = 0xffff; | ||
3417 | |||
3180 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); | 3418 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); |
3181 | 3419 | ||
3182 | if (!pktgen_setup_dev(pkt_dev)) { | 3420 | if (!pktgen_setup_dev(pkt_dev)) { |