diff options
Diffstat (limited to 'net/core/pktgen.c')
| -rw-r--r-- | net/core/pktgen.c | 329 |
1 files changed, 312 insertions, 17 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 67ed14ddabd2..dd023fd28304 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> |
| @@ -157,7 +160,7 @@ | |||
| 157 | #include <asm/div64.h> /* do_div */ | 160 | #include <asm/div64.h> /* do_div */ |
| 158 | #include <asm/timex.h> | 161 | #include <asm/timex.h> |
| 159 | 162 | ||
| 160 | #define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n" | 163 | #define VERSION "pktgen v2.68: Packet Generator for packet performance testing.\n" |
| 161 | 164 | ||
| 162 | /* #define PG_DEBUG(a) a */ | 165 | /* #define PG_DEBUG(a) a */ |
| 163 | #define PG_DEBUG(a) | 166 | #define PG_DEBUG(a) |
| @@ -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; |
| @@ -284,10 +292,23 @@ struct pktgen_dev { | |||
| 284 | __u16 udp_dst_min; /* inclusive, dest UDP port */ | 292 | __u16 udp_dst_min; /* inclusive, dest UDP port */ |
| 285 | __u16 udp_dst_max; /* exclusive, dest UDP port */ | 293 | __u16 udp_dst_max; /* exclusive, dest UDP port */ |
| 286 | 294 | ||
| 295 | /* DSCP + ECN */ | ||
| 296 | __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */ | ||
| 297 | __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */ | ||
| 298 | |||
| 287 | /* MPLS */ | 299 | /* MPLS */ |
| 288 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ | 300 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ |
| 289 | __be32 labels[MAX_MPLS_LABELS]; | 301 | __be32 labels[MAX_MPLS_LABELS]; |
| 290 | 302 | ||
| 303 | /* VLAN/SVLAN (802.1Q/Q-in-Q) */ | ||
| 304 | __u8 vlan_p; | ||
| 305 | __u8 vlan_cfi; | ||
| 306 | __u16 vlan_id; /* 0xffff means no vlan tag */ | ||
| 307 | |||
| 308 | __u8 svlan_p; | ||
| 309 | __u8 svlan_cfi; | ||
| 310 | __u16 svlan_id; /* 0xffff means no svlan tag */ | ||
| 311 | |||
| 291 | __u32 src_mac_count; /* How many MACs to iterate through */ | 312 | __u32 src_mac_count; /* How many MACs to iterate through */ |
| 292 | __u32 dst_mac_count; /* How many MACs to iterate through */ | 313 | __u32 dst_mac_count; /* How many MACs to iterate through */ |
| 293 | 314 | ||
| @@ -644,6 +665,24 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
| 644 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); | 665 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); |
| 645 | } | 666 | } |
| 646 | 667 | ||
| 668 | if (pkt_dev->vlan_id != 0xffff) { | ||
| 669 | seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", | ||
| 670 | pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi); | ||
| 671 | } | ||
| 672 | |||
| 673 | if (pkt_dev->svlan_id != 0xffff) { | ||
| 674 | seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", | ||
| 675 | pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi); | ||
| 676 | } | ||
| 677 | |||
| 678 | if (pkt_dev->tos) { | ||
| 679 | seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); | ||
| 680 | } | ||
| 681 | |||
| 682 | if (pkt_dev->traffic_class) { | ||
| 683 | seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); | ||
| 684 | } | ||
| 685 | |||
| 647 | seq_printf(seq, " Flags: "); | 686 | seq_printf(seq, " Flags: "); |
| 648 | 687 | ||
| 649 | if (pkt_dev->flags & F_IPV6) | 688 | if (pkt_dev->flags & F_IPV6) |
| @@ -673,6 +712,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
| 673 | if (pkt_dev->flags & F_MACDST_RND) | 712 | if (pkt_dev->flags & F_MACDST_RND) |
| 674 | seq_printf(seq, "MACDST_RND "); | 713 | seq_printf(seq, "MACDST_RND "); |
| 675 | 714 | ||
| 715 | if (pkt_dev->flags & F_VID_RND) | ||
| 716 | seq_printf(seq, "VID_RND "); | ||
| 717 | |||
| 718 | if (pkt_dev->flags & F_SVID_RND) | ||
| 719 | seq_printf(seq, "SVID_RND "); | ||
| 720 | |||
| 676 | seq_puts(seq, "\n"); | 721 | seq_puts(seq, "\n"); |
| 677 | 722 | ||
| 678 | sa = pkt_dev->started_at; | 723 | sa = pkt_dev->started_at; |
| @@ -715,12 +760,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
| 715 | } | 760 | } |
| 716 | 761 | ||
| 717 | 762 | ||
| 718 | static int hex32_arg(const char __user *user_buffer, __u32 *num) | 763 | static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num) |
| 719 | { | 764 | { |
| 720 | int i = 0; | 765 | int i = 0; |
| 721 | *num = 0; | 766 | *num = 0; |
| 722 | 767 | ||
| 723 | for(; i < 8; i++) { | 768 | for(; i < maxlen; i++) { |
| 724 | char c; | 769 | char c; |
| 725 | *num <<= 4; | 770 | *num <<= 4; |
| 726 | if (get_user(c, &user_buffer[i])) | 771 | if (get_user(c, &user_buffer[i])) |
| @@ -815,7 +860,7 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) | |||
| 815 | pkt_dev->nr_labels = 0; | 860 | pkt_dev->nr_labels = 0; |
| 816 | do { | 861 | do { |
| 817 | __u32 tmp; | 862 | __u32 tmp; |
| 818 | len = hex32_arg(&buffer[i], &tmp); | 863 | len = hex32_arg(&buffer[i], 8, &tmp); |
| 819 | if (len <= 0) | 864 | if (len <= 0) |
| 820 | return len; | 865 | return len; |
| 821 | pkt_dev->labels[n] = htonl(tmp); | 866 | pkt_dev->labels[n] = htonl(tmp); |
| @@ -1140,11 +1185,27 @@ static ssize_t pktgen_if_write(struct file *file, | |||
| 1140 | else if (strcmp(f, "!MPLS_RND") == 0) | 1185 | else if (strcmp(f, "!MPLS_RND") == 0) |
| 1141 | pkt_dev->flags &= ~F_MPLS_RND; | 1186 | pkt_dev->flags &= ~F_MPLS_RND; |
| 1142 | 1187 | ||
| 1188 | else if (strcmp(f, "VID_RND") == 0) | ||
| 1189 | pkt_dev->flags |= F_VID_RND; | ||
| 1190 | |||
| 1191 | else if (strcmp(f, "!VID_RND") == 0) | ||
| 1192 | pkt_dev->flags &= ~F_VID_RND; | ||
| 1193 | |||
| 1194 | else if (strcmp(f, "SVID_RND") == 0) | ||
| 1195 | pkt_dev->flags |= F_SVID_RND; | ||
| 1196 | |||
| 1197 | else if (strcmp(f, "!SVID_RND") == 0) | ||
| 1198 | pkt_dev->flags &= ~F_SVID_RND; | ||
| 1199 | |||
| 1200 | else if (strcmp(f, "!IPV6") == 0) | ||
| 1201 | pkt_dev->flags &= ~F_IPV6; | ||
| 1202 | |||
| 1143 | else { | 1203 | else { |
| 1144 | sprintf(pg_result, | 1204 | sprintf(pg_result, |
| 1145 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | 1205 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", |
| 1146 | f, | 1206 | f, |
| 1147 | "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); | 1207 | "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " |
| 1208 | "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n"); | ||
| 1148 | return count; | 1209 | return count; |
| 1149 | } | 1210 | } |
| 1150 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); | 1211 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); |
| @@ -1445,6 +1506,160 @@ static ssize_t pktgen_if_write(struct file *file, | |||
| 1445 | offset += sprintf(pg_result + offset, | 1506 | offset += sprintf(pg_result + offset, |
| 1446 | "%08x%s", ntohl(pkt_dev->labels[n]), | 1507 | "%08x%s", ntohl(pkt_dev->labels[n]), |
| 1447 | n == pkt_dev->nr_labels-1 ? "" : ","); | 1508 | n == pkt_dev->nr_labels-1 ? "" : ","); |
| 1509 | |||
| 1510 | if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { | ||
| 1511 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
| 1512 | pkt_dev->svlan_id = 0xffff; | ||
| 1513 | |||
| 1514 | if (debug) | ||
| 1515 | printk("pktgen: VLAN/SVLAN auto turned off\n"); | ||
| 1516 | } | ||
| 1517 | return count; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | if (!strcmp(name, "vlan_id")) { | ||
| 1521 | len = num_arg(&user_buffer[i], 4, &value); | ||
| 1522 | if (len < 0) { | ||
| 1523 | return len; | ||
| 1524 | } | ||
| 1525 | i += len; | ||
| 1526 | if (value <= 4095) { | ||
| 1527 | pkt_dev->vlan_id = value; /* turn on VLAN */ | ||
| 1528 | |||
| 1529 | if (debug) | ||
| 1530 | printk("pktgen: VLAN turned on\n"); | ||
| 1531 | |||
| 1532 | if (debug && pkt_dev->nr_labels) | ||
| 1533 | printk("pktgen: MPLS auto turned off\n"); | ||
| 1534 | |||
| 1535 | pkt_dev->nr_labels = 0; /* turn off MPLS */ | ||
| 1536 | sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); | ||
| 1537 | } else { | ||
| 1538 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
| 1539 | pkt_dev->svlan_id = 0xffff; | ||
| 1540 | |||
| 1541 | if (debug) | ||
| 1542 | printk("pktgen: VLAN/SVLAN turned off\n"); | ||
| 1543 | } | ||
| 1544 | return count; | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | if (!strcmp(name, "vlan_p")) { | ||
| 1548 | len = num_arg(&user_buffer[i], 1, &value); | ||
| 1549 | if (len < 0) { | ||
| 1550 | return len; | ||
| 1551 | } | ||
| 1552 | i += len; | ||
| 1553 | if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { | ||
| 1554 | pkt_dev->vlan_p = value; | ||
| 1555 | sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); | ||
| 1556 | } else { | ||
| 1557 | sprintf(pg_result, "ERROR: vlan_p must be 0-7"); | ||
| 1558 | } | ||
| 1559 | return count; | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | if (!strcmp(name, "vlan_cfi")) { | ||
| 1563 | len = num_arg(&user_buffer[i], 1, &value); | ||
| 1564 | if (len < 0) { | ||
| 1565 | return len; | ||
| 1566 | } | ||
| 1567 | i += len; | ||
| 1568 | if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { | ||
| 1569 | pkt_dev->vlan_cfi = value; | ||
| 1570 | sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); | ||
| 1571 | } else { | ||
| 1572 | sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); | ||
| 1573 | } | ||
| 1574 | return count; | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | if (!strcmp(name, "svlan_id")) { | ||
| 1578 | len = num_arg(&user_buffer[i], 4, &value); | ||
| 1579 | if (len < 0) { | ||
| 1580 | return len; | ||
| 1581 | } | ||
| 1582 | i += len; | ||
| 1583 | if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { | ||
| 1584 | pkt_dev->svlan_id = value; /* turn on SVLAN */ | ||
| 1585 | |||
| 1586 | if (debug) | ||
| 1587 | printk("pktgen: SVLAN turned on\n"); | ||
| 1588 | |||
| 1589 | if (debug && pkt_dev->nr_labels) | ||
| 1590 | printk("pktgen: MPLS auto turned off\n"); | ||
| 1591 | |||
| 1592 | pkt_dev->nr_labels = 0; /* turn off MPLS */ | ||
| 1593 | sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); | ||
| 1594 | } else { | ||
| 1595 | pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ | ||
| 1596 | pkt_dev->svlan_id = 0xffff; | ||
| 1597 | |||
| 1598 | if (debug) | ||
| 1599 | printk("pktgen: VLAN/SVLAN turned off\n"); | ||
| 1600 | } | ||
| 1601 | return count; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | if (!strcmp(name, "svlan_p")) { | ||
| 1605 | len = num_arg(&user_buffer[i], 1, &value); | ||
| 1606 | if (len < 0) { | ||
| 1607 | return len; | ||
| 1608 | } | ||
| 1609 | i += len; | ||
| 1610 | if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { | ||
| 1611 | pkt_dev->svlan_p = value; | ||
| 1612 | sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); | ||
| 1613 | } else { | ||
| 1614 | sprintf(pg_result, "ERROR: svlan_p must be 0-7"); | ||
| 1615 | } | ||
| 1616 | return count; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | if (!strcmp(name, "svlan_cfi")) { | ||
| 1620 | len = num_arg(&user_buffer[i], 1, &value); | ||
| 1621 | if (len < 0) { | ||
| 1622 | return len; | ||
| 1623 | } | ||
| 1624 | i += len; | ||
| 1625 | if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { | ||
| 1626 | pkt_dev->svlan_cfi = value; | ||
| 1627 | sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); | ||
| 1628 | } else { | ||
| 1629 | sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); | ||
| 1630 | } | ||
| 1631 | return count; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | if (!strcmp(name, "tos")) { | ||
| 1635 | __u32 tmp_value = 0; | ||
| 1636 | len = hex32_arg(&user_buffer[i], 2, &tmp_value); | ||
| 1637 | if (len < 0) { | ||
| 1638 | return len; | ||
| 1639 | } | ||
| 1640 | i += len; | ||
| 1641 | if (len == 2) { | ||
| 1642 | pkt_dev->tos = tmp_value; | ||
| 1643 | sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); | ||
| 1644 | } else { | ||
| 1645 | sprintf(pg_result, "ERROR: tos must be 00-ff"); | ||
| 1646 | } | ||
| 1647 | return count; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | if (!strcmp(name, "traffic_class")) { | ||
| 1651 | __u32 tmp_value = 0; | ||
| 1652 | len = hex32_arg(&user_buffer[i], 2, &tmp_value); | ||
| 1653 | if (len < 0) { | ||
| 1654 | return len; | ||
| 1655 | } | ||
| 1656 | i += len; | ||
| 1657 | if (len == 2) { | ||
| 1658 | pkt_dev->traffic_class = tmp_value; | ||
| 1659 | sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); | ||
| 1660 | } else { | ||
| 1661 | sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); | ||
| 1662 | } | ||
| 1448 | return count; | 1663 | return count; |
| 1449 | } | 1664 | } |
| 1450 | 1665 | ||
| @@ -1786,7 +2001,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
| 1786 | * use ipv6_get_lladdr if/when it's get exported | 2001 | * use ipv6_get_lladdr if/when it's get exported |
| 1787 | */ | 2002 | */ |
| 1788 | 2003 | ||
| 1789 | read_lock(&addrconf_lock); | 2004 | rcu_read_lock(); |
| 1790 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { | 2005 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { |
| 1791 | struct inet6_ifaddr *ifp; | 2006 | struct inet6_ifaddr *ifp; |
| 1792 | 2007 | ||
| @@ -1805,7 +2020,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
| 1805 | } | 2020 | } |
| 1806 | read_unlock_bh(&idev->lock); | 2021 | read_unlock_bh(&idev->lock); |
| 1807 | } | 2022 | } |
| 1808 | read_unlock(&addrconf_lock); | 2023 | rcu_read_unlock(); |
| 1809 | if (err) | 2024 | if (err) |
| 1810 | printk("pktgen: ERROR: IPv6 link address not availble.\n"); | 2025 | printk("pktgen: ERROR: IPv6 link address not availble.\n"); |
| 1811 | } | 2026 | } |
| @@ -1949,6 +2164,14 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
| 1949 | htonl(0x000fffff)); | 2164 | htonl(0x000fffff)); |
| 1950 | } | 2165 | } |
| 1951 | 2166 | ||
| 2167 | if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { | ||
| 2168 | pkt_dev->vlan_id = pktgen_random() % 4096; | ||
| 2169 | } | ||
| 2170 | |||
| 2171 | if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { | ||
| 2172 | pkt_dev->svlan_id = pktgen_random() % 4096; | ||
| 2173 | } | ||
| 2174 | |||
| 1952 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { | 2175 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { |
| 1953 | if (pkt_dev->flags & F_UDPSRC_RND) | 2176 | if (pkt_dev->flags & F_UDPSRC_RND) |
| 1954 | pkt_dev->cur_udp_src = | 2177 | pkt_dev->cur_udp_src = |
| @@ -2092,10 +2315,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2092 | struct pktgen_hdr *pgh = NULL; | 2315 | struct pktgen_hdr *pgh = NULL; |
| 2093 | __be16 protocol = __constant_htons(ETH_P_IP); | 2316 | __be16 protocol = __constant_htons(ETH_P_IP); |
| 2094 | __be32 *mpls; | 2317 | __be32 *mpls; |
| 2318 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | ||
| 2319 | __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ | ||
| 2320 | __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ | ||
| 2321 | __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ | ||
| 2322 | |||
| 2095 | 2323 | ||
| 2096 | if (pkt_dev->nr_labels) | 2324 | if (pkt_dev->nr_labels) |
| 2097 | protocol = __constant_htons(ETH_P_MPLS_UC); | 2325 | protocol = __constant_htons(ETH_P_MPLS_UC); |
| 2098 | 2326 | ||
| 2327 | if (pkt_dev->vlan_id != 0xffff) | ||
| 2328 | protocol = __constant_htons(ETH_P_8021Q); | ||
| 2329 | |||
| 2099 | /* Update any of the values, used when we're incrementing various | 2330 | /* Update any of the values, used when we're incrementing various |
| 2100 | * fields. | 2331 | * fields. |
| 2101 | */ | 2332 | */ |
| @@ -2103,7 +2334,9 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2103 | 2334 | ||
| 2104 | datalen = (odev->hard_header_len + 16) & ~0xf; | 2335 | datalen = (odev->hard_header_len + 16) & ~0xf; |
| 2105 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + | 2336 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + |
| 2106 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | 2337 | pkt_dev->nr_labels*sizeof(u32) + |
| 2338 | VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev), | ||
| 2339 | GFP_ATOMIC); | ||
| 2107 | if (!skb) { | 2340 | if (!skb) { |
| 2108 | sprintf(pkt_dev->result, "No memory"); | 2341 | sprintf(pkt_dev->result, "No memory"); |
| 2109 | return NULL; | 2342 | return NULL; |
| @@ -2116,6 +2349,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2116 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | 2349 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); |
| 2117 | if (pkt_dev->nr_labels) | 2350 | if (pkt_dev->nr_labels) |
| 2118 | mpls_push(mpls, pkt_dev); | 2351 | mpls_push(mpls, pkt_dev); |
| 2352 | |||
| 2353 | if (pkt_dev->vlan_id != 0xffff) { | ||
| 2354 | if(pkt_dev->svlan_id != 0xffff) { | ||
| 2355 | svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2356 | *svlan_tci = htons(pkt_dev->svlan_id); | ||
| 2357 | *svlan_tci |= pkt_dev->svlan_p << 5; | ||
| 2358 | *svlan_tci |= pkt_dev->svlan_cfi << 4; | ||
| 2359 | svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2360 | *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q); | ||
| 2361 | } | ||
| 2362 | vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2363 | *vlan_tci = htons(pkt_dev->vlan_id); | ||
| 2364 | *vlan_tci |= pkt_dev->vlan_p << 5; | ||
| 2365 | *vlan_tci |= pkt_dev->vlan_cfi << 4; | ||
| 2366 | vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2367 | *vlan_encapsulated_proto = __constant_htons(ETH_P_IP); | ||
| 2368 | } | ||
| 2369 | |||
| 2119 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); | 2370 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); |
| 2120 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2371 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
| 2121 | 2372 | ||
| @@ -2124,7 +2375,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2124 | 2375 | ||
| 2125 | /* Eth + IPh + UDPh + mpls */ | 2376 | /* Eth + IPh + UDPh + mpls */ |
| 2126 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - | 2377 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - |
| 2127 | pkt_dev->nr_labels*sizeof(u32); | 2378 | pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); |
| 2128 | if (datalen < sizeof(struct pktgen_hdr)) | 2379 | if (datalen < sizeof(struct pktgen_hdr)) |
| 2129 | datalen = sizeof(struct pktgen_hdr); | 2380 | datalen = sizeof(struct pktgen_hdr); |
| 2130 | 2381 | ||
| @@ -2136,7 +2387,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2136 | iph->ihl = 5; | 2387 | iph->ihl = 5; |
| 2137 | iph->version = 4; | 2388 | iph->version = 4; |
| 2138 | iph->ttl = 32; | 2389 | iph->ttl = 32; |
| 2139 | iph->tos = 0; | 2390 | iph->tos = pkt_dev->tos; |
| 2140 | iph->protocol = IPPROTO_UDP; /* UDP */ | 2391 | iph->protocol = IPPROTO_UDP; /* UDP */ |
| 2141 | iph->saddr = pkt_dev->cur_saddr; | 2392 | iph->saddr = pkt_dev->cur_saddr; |
| 2142 | iph->daddr = pkt_dev->cur_daddr; | 2393 | iph->daddr = pkt_dev->cur_daddr; |
| @@ -2146,9 +2397,12 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2146 | iph->check = 0; | 2397 | iph->check = 0; |
| 2147 | iph->check = ip_fast_csum((void *)iph, iph->ihl); | 2398 | iph->check = ip_fast_csum((void *)iph, iph->ihl); |
| 2148 | skb->protocol = protocol; | 2399 | skb->protocol = protocol; |
| 2149 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); | 2400 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) - |
| 2401 | VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); | ||
| 2150 | skb->dev = odev; | 2402 | skb->dev = odev; |
| 2151 | skb->pkt_type = PACKET_HOST; | 2403 | skb->pkt_type = PACKET_HOST; |
| 2404 | skb->nh.iph = iph; | ||
| 2405 | skb->h.uh = udph; | ||
| 2152 | 2406 | ||
| 2153 | if (pkt_dev->nfrags <= 0) | 2407 | if (pkt_dev->nfrags <= 0) |
| 2154 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | 2408 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); |
| @@ -2216,7 +2470,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
| 2216 | pgh->tv_sec = htonl(timestamp.tv_sec); | 2470 | pgh->tv_sec = htonl(timestamp.tv_sec); |
| 2217 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2471 | pgh->tv_usec = htonl(timestamp.tv_usec); |
| 2218 | } | 2472 | } |
| 2219 | pkt_dev->seq_num++; | ||
| 2220 | 2473 | ||
| 2221 | return skb; | 2474 | return skb; |
| 2222 | } | 2475 | } |
| @@ -2400,17 +2653,26 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
| 2400 | struct pktgen_hdr *pgh = NULL; | 2653 | struct pktgen_hdr *pgh = NULL; |
| 2401 | __be16 protocol = __constant_htons(ETH_P_IPV6); | 2654 | __be16 protocol = __constant_htons(ETH_P_IPV6); |
| 2402 | __be32 *mpls; | 2655 | __be32 *mpls; |
| 2656 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | ||
| 2657 | __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ | ||
| 2658 | __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ | ||
| 2659 | __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ | ||
| 2403 | 2660 | ||
| 2404 | if (pkt_dev->nr_labels) | 2661 | if (pkt_dev->nr_labels) |
| 2405 | protocol = __constant_htons(ETH_P_MPLS_UC); | 2662 | protocol = __constant_htons(ETH_P_MPLS_UC); |
| 2406 | 2663 | ||
| 2664 | if (pkt_dev->vlan_id != 0xffff) | ||
| 2665 | protocol = __constant_htons(ETH_P_8021Q); | ||
| 2666 | |||
| 2407 | /* Update any of the values, used when we're incrementing various | 2667 | /* Update any of the values, used when we're incrementing various |
| 2408 | * fields. | 2668 | * fields. |
| 2409 | */ | 2669 | */ |
| 2410 | mod_cur_headers(pkt_dev); | 2670 | mod_cur_headers(pkt_dev); |
| 2411 | 2671 | ||
| 2412 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + | 2672 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + |
| 2413 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | 2673 | pkt_dev->nr_labels*sizeof(u32) + |
| 2674 | VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev), | ||
| 2675 | GFP_ATOMIC); | ||
| 2414 | if (!skb) { | 2676 | if (!skb) { |
| 2415 | sprintf(pkt_dev->result, "No memory"); | 2677 | sprintf(pkt_dev->result, "No memory"); |
| 2416 | return NULL; | 2678 | return NULL; |
| @@ -2423,16 +2685,34 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
| 2423 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | 2685 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); |
| 2424 | if (pkt_dev->nr_labels) | 2686 | if (pkt_dev->nr_labels) |
| 2425 | mpls_push(mpls, pkt_dev); | 2687 | mpls_push(mpls, pkt_dev); |
| 2688 | |||
| 2689 | if (pkt_dev->vlan_id != 0xffff) { | ||
| 2690 | if(pkt_dev->svlan_id != 0xffff) { | ||
| 2691 | svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2692 | *svlan_tci = htons(pkt_dev->svlan_id); | ||
| 2693 | *svlan_tci |= pkt_dev->svlan_p << 5; | ||
| 2694 | *svlan_tci |= pkt_dev->svlan_cfi << 4; | ||
| 2695 | svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2696 | *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q); | ||
| 2697 | } | ||
| 2698 | vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2699 | *vlan_tci = htons(pkt_dev->vlan_id); | ||
| 2700 | *vlan_tci |= pkt_dev->vlan_p << 5; | ||
| 2701 | *vlan_tci |= pkt_dev->vlan_cfi << 4; | ||
| 2702 | vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); | ||
| 2703 | *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6); | ||
| 2704 | } | ||
| 2705 | |||
| 2426 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); | 2706 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); |
| 2427 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2707 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
| 2428 | 2708 | ||
| 2429 | memcpy(eth, pkt_dev->hh, 12); | 2709 | memcpy(eth, pkt_dev->hh, 12); |
| 2430 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); | 2710 | *(u16 *) & eth[12] = protocol; |
| 2431 | 2711 | ||
| 2432 | /* Eth + IPh + UDPh + mpls */ | 2712 | /* Eth + IPh + UDPh + mpls */ |
| 2433 | datalen = pkt_dev->cur_pkt_size - 14 - | 2713 | datalen = pkt_dev->cur_pkt_size - 14 - |
| 2434 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - | 2714 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - |
| 2435 | pkt_dev->nr_labels*sizeof(u32); | 2715 | pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); |
| 2436 | 2716 | ||
| 2437 | if (datalen < sizeof(struct pktgen_hdr)) { | 2717 | if (datalen < sizeof(struct pktgen_hdr)) { |
| 2438 | datalen = sizeof(struct pktgen_hdr); | 2718 | datalen = sizeof(struct pktgen_hdr); |
| @@ -2448,6 +2728,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
| 2448 | 2728 | ||
| 2449 | *(u32 *) iph = __constant_htonl(0x60000000); /* Version + flow */ | 2729 | *(u32 *) iph = __constant_htonl(0x60000000); /* Version + flow */ |
| 2450 | 2730 | ||
| 2731 | if (pkt_dev->traffic_class) { | ||
| 2732 | /* Version + traffic class + flow (0) */ | ||
| 2733 | *(u32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); | ||
| 2734 | } | ||
| 2735 | |||
| 2451 | iph->hop_limit = 32; | 2736 | iph->hop_limit = 32; |
| 2452 | 2737 | ||
| 2453 | iph->payload_len = htons(sizeof(struct udphdr) + datalen); | 2738 | iph->payload_len = htons(sizeof(struct udphdr) + datalen); |
| @@ -2456,10 +2741,13 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
| 2456 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); | 2741 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); |
| 2457 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); | 2742 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); |
| 2458 | 2743 | ||
| 2459 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); | 2744 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) - |
| 2745 | VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev); | ||
| 2460 | skb->protocol = protocol; | 2746 | skb->protocol = protocol; |
| 2461 | skb->dev = odev; | 2747 | skb->dev = odev; |
| 2462 | skb->pkt_type = PACKET_HOST; | 2748 | skb->pkt_type = PACKET_HOST; |
| 2749 | skb->nh.ipv6h = iph; | ||
| 2750 | skb->h.uh = udph; | ||
| 2463 | 2751 | ||
| 2464 | if (pkt_dev->nfrags <= 0) | 2752 | if (pkt_dev->nfrags <= 0) |
| 2465 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | 2753 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); |
| @@ -2527,7 +2815,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
| 2527 | pgh->tv_sec = htonl(timestamp.tv_sec); | 2815 | pgh->tv_sec = htonl(timestamp.tv_sec); |
| 2528 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2816 | pgh->tv_usec = htonl(timestamp.tv_usec); |
| 2529 | } | 2817 | } |
| 2530 | pkt_dev->seq_num++; | 2818 | /* pkt_dev->seq_num++; FF: you really mean this? */ |
| 2531 | 2819 | ||
| 2532 | return skb; | 2820 | return skb; |
| 2533 | } | 2821 | } |
| @@ -3173,6 +3461,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
| 3173 | pkt_dev->udp_dst_min = 9; | 3461 | pkt_dev->udp_dst_min = 9; |
| 3174 | pkt_dev->udp_dst_max = 9; | 3462 | pkt_dev->udp_dst_max = 9; |
| 3175 | 3463 | ||
| 3464 | pkt_dev->vlan_p = 0; | ||
| 3465 | pkt_dev->vlan_cfi = 0; | ||
| 3466 | pkt_dev->vlan_id = 0xffff; | ||
| 3467 | pkt_dev->svlan_p = 0; | ||
| 3468 | pkt_dev->svlan_cfi = 0; | ||
| 3469 | pkt_dev->svlan_id = 0xffff; | ||
| 3470 | |||
| 3176 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); | 3471 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); |
| 3177 | 3472 | ||
| 3178 | if (!pktgen_setup_dev(pkt_dev)) { | 3473 | if (!pktgen_setup_dev(pkt_dev)) { |
