diff options
Diffstat (limited to 'net/core/pktgen.c')
-rw-r--r-- | net/core/pktgen.c | 507 |
1 files changed, 176 insertions, 331 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 10a1ea72010d..f76079cd750c 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -156,6 +156,7 @@ | |||
156 | #include <linux/wait.h> | 156 | #include <linux/wait.h> |
157 | #include <linux/etherdevice.h> | 157 | #include <linux/etherdevice.h> |
158 | #include <linux/kthread.h> | 158 | #include <linux/kthread.h> |
159 | #include <linux/prefetch.h> | ||
159 | #include <net/net_namespace.h> | 160 | #include <net/net_namespace.h> |
160 | #include <net/checksum.h> | 161 | #include <net/checksum.h> |
161 | #include <net/ipv6.h> | 162 | #include <net/ipv6.h> |
@@ -251,6 +252,7 @@ struct pktgen_dev { | |||
251 | int max_pkt_size; /* = ETH_ZLEN; */ | 252 | int max_pkt_size; /* = ETH_ZLEN; */ |
252 | int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ | 253 | int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ |
253 | int nfrags; | 254 | int nfrags; |
255 | struct page *page; | ||
254 | u64 delay; /* nano-seconds */ | 256 | u64 delay; /* nano-seconds */ |
255 | 257 | ||
256 | __u64 count; /* Default No packets to send */ | 258 | __u64 count; /* Default No packets to send */ |
@@ -378,6 +380,7 @@ struct pktgen_dev { | |||
378 | 380 | ||
379 | u16 queue_map_min; | 381 | u16 queue_map_min; |
380 | u16 queue_map_max; | 382 | u16 queue_map_max; |
383 | __u32 skb_priority; /* skb priority field */ | ||
381 | int node; /* Memory node */ | 384 | int node; /* Memory node */ |
382 | 385 | ||
383 | #ifdef CONFIG_XFRM | 386 | #ifdef CONFIG_XFRM |
@@ -394,6 +397,8 @@ struct pktgen_hdr { | |||
394 | __be32 tv_usec; | 397 | __be32 tv_usec; |
395 | }; | 398 | }; |
396 | 399 | ||
400 | static bool pktgen_exiting __read_mostly; | ||
401 | |||
397 | struct pktgen_thread { | 402 | struct pktgen_thread { |
398 | spinlock_t if_lock; /* for list of devices */ | 403 | spinlock_t if_lock; /* for list of devices */ |
399 | struct list_head if_list; /* All device here */ | 404 | struct list_head if_list; /* All device here */ |
@@ -445,7 +450,6 @@ static void pktgen_stop(struct pktgen_thread *t); | |||
445 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); | 450 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); |
446 | 451 | ||
447 | static unsigned int scan_ip6(const char *s, char ip[16]); | 452 | static unsigned int scan_ip6(const char *s, char ip[16]); |
448 | static unsigned int fmt_ip6(char *s, const char ip[16]); | ||
449 | 453 | ||
450 | /* Module parameters, defaults. */ | 454 | /* Module parameters, defaults. */ |
451 | static int pg_count_d __read_mostly = 1000; | 455 | static int pg_count_d __read_mostly = 1000; |
@@ -547,22 +551,18 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
547 | pkt_dev->queue_map_min, | 551 | pkt_dev->queue_map_min, |
548 | pkt_dev->queue_map_max); | 552 | pkt_dev->queue_map_max); |
549 | 553 | ||
550 | if (pkt_dev->flags & F_IPV6) { | 554 | if (pkt_dev->skb_priority) |
551 | char b1[128], b2[128], b3[128]; | 555 | seq_printf(seq, " skb_priority: %u\n", |
552 | fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); | 556 | pkt_dev->skb_priority); |
553 | fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); | ||
554 | fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); | ||
555 | seq_printf(seq, | ||
556 | " saddr: %s min_saddr: %s max_saddr: %s\n", b1, | ||
557 | b2, b3); | ||
558 | 557 | ||
559 | fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); | 558 | if (pkt_dev->flags & F_IPV6) { |
560 | fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); | ||
561 | fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); | ||
562 | seq_printf(seq, | 559 | seq_printf(seq, |
563 | " daddr: %s min_daddr: %s max_daddr: %s\n", b1, | 560 | " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" |
564 | b2, b3); | 561 | " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", |
565 | 562 | &pkt_dev->in6_saddr, | |
563 | &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, | ||
564 | &pkt_dev->in6_daddr, | ||
565 | &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); | ||
566 | } else { | 566 | } else { |
567 | seq_printf(seq, | 567 | seq_printf(seq, |
568 | " dst_min: %s dst_max: %s\n", | 568 | " dst_min: %s dst_max: %s\n", |
@@ -698,10 +698,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
698 | pkt_dev->cur_src_mac_offset); | 698 | pkt_dev->cur_src_mac_offset); |
699 | 699 | ||
700 | if (pkt_dev->flags & F_IPV6) { | 700 | if (pkt_dev->flags & F_IPV6) { |
701 | char b1[128], b2[128]; | 701 | seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", |
702 | fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); | 702 | &pkt_dev->cur_in6_saddr, |
703 | fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); | 703 | &pkt_dev->cur_in6_daddr); |
704 | seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); | ||
705 | } else | 704 | } else |
706 | seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", | 705 | seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", |
707 | pkt_dev->cur_saddr, pkt_dev->cur_daddr); | 706 | pkt_dev->cur_saddr, pkt_dev->cur_daddr); |
@@ -729,16 +728,14 @@ static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, | |||
729 | *num = 0; | 728 | *num = 0; |
730 | 729 | ||
731 | for (; i < maxlen; i++) { | 730 | for (; i < maxlen; i++) { |
731 | int value; | ||
732 | char c; | 732 | char c; |
733 | *num <<= 4; | 733 | *num <<= 4; |
734 | if (get_user(c, &user_buffer[i])) | 734 | if (get_user(c, &user_buffer[i])) |
735 | return -EFAULT; | 735 | return -EFAULT; |
736 | if ((c >= '0') && (c <= '9')) | 736 | value = hex_to_bin(c); |
737 | *num |= c - '0'; | 737 | if (value >= 0) |
738 | else if ((c >= 'a') && (c <= 'f')) | 738 | *num |= value; |
739 | *num |= c - 'a' + 10; | ||
740 | else if ((c >= 'A') && (c <= 'F')) | ||
741 | *num |= c - 'A' + 10; | ||
742 | else | 739 | else |
743 | break; | 740 | break; |
744 | } | 741 | } |
@@ -773,10 +770,10 @@ done: | |||
773 | static unsigned long num_arg(const char __user * user_buffer, | 770 | static unsigned long num_arg(const char __user * user_buffer, |
774 | unsigned long maxlen, unsigned long *num) | 771 | unsigned long maxlen, unsigned long *num) |
775 | { | 772 | { |
776 | int i = 0; | 773 | int i; |
777 | *num = 0; | 774 | *num = 0; |
778 | 775 | ||
779 | for (; i < maxlen; i++) { | 776 | for (i = 0; i < maxlen; i++) { |
780 | char c; | 777 | char c; |
781 | if (get_user(c, &user_buffer[i])) | 778 | if (get_user(c, &user_buffer[i])) |
782 | return -EFAULT; | 779 | return -EFAULT; |
@@ -791,9 +788,9 @@ static unsigned long num_arg(const char __user * user_buffer, | |||
791 | 788 | ||
792 | static int strn_len(const char __user * user_buffer, unsigned int maxlen) | 789 | static int strn_len(const char __user * user_buffer, unsigned int maxlen) |
793 | { | 790 | { |
794 | int i = 0; | 791 | int i; |
795 | 792 | ||
796 | for (; i < maxlen; i++) { | 793 | for (i = 0; i < maxlen; i++) { |
797 | char c; | 794 | char c; |
798 | if (get_user(c, &user_buffer[i])) | 795 | if (get_user(c, &user_buffer[i])) |
799 | return -EFAULT; | 796 | return -EFAULT; |
@@ -848,7 +845,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
848 | { | 845 | { |
849 | struct seq_file *seq = file->private_data; | 846 | struct seq_file *seq = file->private_data; |
850 | struct pktgen_dev *pkt_dev = seq->private; | 847 | struct pktgen_dev *pkt_dev = seq->private; |
851 | int i = 0, max, len; | 848 | int i, max, len; |
852 | char name[16], valstr[32]; | 849 | char name[16], valstr[32]; |
853 | unsigned long value = 0; | 850 | unsigned long value = 0; |
854 | char *pg_result = NULL; | 851 | char *pg_result = NULL; |
@@ -862,13 +859,13 @@ static ssize_t pktgen_if_write(struct file *file, | |||
862 | return -EINVAL; | 859 | return -EINVAL; |
863 | } | 860 | } |
864 | 861 | ||
865 | max = count - i; | 862 | max = count; |
866 | tmp = count_trail_chars(&user_buffer[i], max); | 863 | tmp = count_trail_chars(user_buffer, max); |
867 | if (tmp < 0) { | 864 | if (tmp < 0) { |
868 | pr_warning("illegal format\n"); | 865 | pr_warning("illegal format\n"); |
869 | return tmp; | 866 | return tmp; |
870 | } | 867 | } |
871 | i += tmp; | 868 | i = tmp; |
872 | 869 | ||
873 | /* Read variable name */ | 870 | /* Read variable name */ |
874 | 871 | ||
@@ -889,10 +886,11 @@ static ssize_t pktgen_if_write(struct file *file, | |||
889 | i += len; | 886 | i += len; |
890 | 887 | ||
891 | if (debug) { | 888 | if (debug) { |
892 | char tb[count + 1]; | 889 | size_t copy = min_t(size_t, count, 1023); |
893 | if (copy_from_user(tb, user_buffer, count)) | 890 | char tb[copy + 1]; |
891 | if (copy_from_user(tb, user_buffer, copy)) | ||
894 | return -EFAULT; | 892 | return -EFAULT; |
895 | tb[count] = 0; | 893 | tb[copy] = 0; |
896 | printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, | 894 | printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, |
897 | (unsigned long)count, tb); | 895 | (unsigned long)count, tb); |
898 | } | 896 | } |
@@ -1128,6 +1126,10 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1128 | if (node_possible(value)) { | 1126 | if (node_possible(value)) { |
1129 | pkt_dev->node = value; | 1127 | pkt_dev->node = value; |
1130 | sprintf(pg_result, "OK: node=%d", pkt_dev->node); | 1128 | sprintf(pg_result, "OK: node=%d", pkt_dev->node); |
1129 | if (pkt_dev->page) { | ||
1130 | put_page(pkt_dev->page); | ||
1131 | pkt_dev->page = NULL; | ||
1132 | } | ||
1131 | } | 1133 | } |
1132 | else | 1134 | else |
1133 | sprintf(pg_result, "ERROR: node not possible"); | 1135 | sprintf(pg_result, "ERROR: node not possible"); |
@@ -1298,7 +1300,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1298 | buf[len] = 0; | 1300 | buf[len] = 0; |
1299 | 1301 | ||
1300 | scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); | 1302 | scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); |
1301 | fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); | 1303 | snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr); |
1302 | 1304 | ||
1303 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); | 1305 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); |
1304 | 1306 | ||
@@ -1321,7 +1323,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1321 | buf[len] = 0; | 1323 | buf[len] = 0; |
1322 | 1324 | ||
1323 | scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); | 1325 | scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); |
1324 | fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); | 1326 | snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr); |
1325 | 1327 | ||
1326 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, | 1328 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, |
1327 | &pkt_dev->min_in6_daddr); | 1329 | &pkt_dev->min_in6_daddr); |
@@ -1344,7 +1346,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1344 | buf[len] = 0; | 1346 | buf[len] = 0; |
1345 | 1347 | ||
1346 | scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); | 1348 | scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); |
1347 | fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); | 1349 | snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr); |
1348 | 1350 | ||
1349 | if (debug) | 1351 | if (debug) |
1350 | printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); | 1352 | printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); |
@@ -1365,7 +1367,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1365 | buf[len] = 0; | 1367 | buf[len] = 0; |
1366 | 1368 | ||
1367 | scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); | 1369 | scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); |
1368 | fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); | 1370 | snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr); |
1369 | 1371 | ||
1370 | ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); | 1372 | ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); |
1371 | 1373 | ||
@@ -1419,11 +1421,6 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1419 | return count; | 1421 | return count; |
1420 | } | 1422 | } |
1421 | if (!strcmp(name, "dst_mac")) { | 1423 | if (!strcmp(name, "dst_mac")) { |
1422 | char *v = valstr; | ||
1423 | unsigned char old_dmac[ETH_ALEN]; | ||
1424 | unsigned char *m = pkt_dev->dst_mac; | ||
1425 | memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); | ||
1426 | |||
1427 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); | 1424 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); |
1428 | if (len < 0) | 1425 | if (len < 0) |
1429 | return len; | 1426 | return len; |
@@ -1431,35 +1428,16 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1431 | memset(valstr, 0, sizeof(valstr)); | 1428 | memset(valstr, 0, sizeof(valstr)); |
1432 | if (copy_from_user(valstr, &user_buffer[i], len)) | 1429 | if (copy_from_user(valstr, &user_buffer[i], len)) |
1433 | return -EFAULT; | 1430 | return -EFAULT; |
1434 | i += len; | ||
1435 | |||
1436 | for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { | ||
1437 | int value; | ||
1438 | |||
1439 | value = hex_to_bin(*v); | ||
1440 | if (value >= 0) | ||
1441 | *m = *m * 16 + value; | ||
1442 | |||
1443 | if (*v == ':') { | ||
1444 | m++; | ||
1445 | *m = 0; | ||
1446 | } | ||
1447 | } | ||
1448 | 1431 | ||
1432 | if (!mac_pton(valstr, pkt_dev->dst_mac)) | ||
1433 | return -EINVAL; | ||
1449 | /* Set up Dest MAC */ | 1434 | /* Set up Dest MAC */ |
1450 | if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) | 1435 | memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN); |
1451 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); | ||
1452 | 1436 | ||
1453 | sprintf(pg_result, "OK: dstmac"); | 1437 | sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); |
1454 | return count; | 1438 | return count; |
1455 | } | 1439 | } |
1456 | if (!strcmp(name, "src_mac")) { | 1440 | if (!strcmp(name, "src_mac")) { |
1457 | char *v = valstr; | ||
1458 | unsigned char old_smac[ETH_ALEN]; | ||
1459 | unsigned char *m = pkt_dev->src_mac; | ||
1460 | |||
1461 | memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); | ||
1462 | |||
1463 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); | 1441 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); |
1464 | if (len < 0) | 1442 | if (len < 0) |
1465 | return len; | 1443 | return len; |
@@ -1467,26 +1445,13 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1467 | memset(valstr, 0, sizeof(valstr)); | 1445 | memset(valstr, 0, sizeof(valstr)); |
1468 | if (copy_from_user(valstr, &user_buffer[i], len)) | 1446 | if (copy_from_user(valstr, &user_buffer[i], len)) |
1469 | return -EFAULT; | 1447 | return -EFAULT; |
1470 | i += len; | ||
1471 | |||
1472 | for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { | ||
1473 | int value; | ||
1474 | |||
1475 | value = hex_to_bin(*v); | ||
1476 | if (value >= 0) | ||
1477 | *m = *m * 16 + value; | ||
1478 | |||
1479 | if (*v == ':') { | ||
1480 | m++; | ||
1481 | *m = 0; | ||
1482 | } | ||
1483 | } | ||
1484 | 1448 | ||
1449 | if (!mac_pton(valstr, pkt_dev->src_mac)) | ||
1450 | return -EINVAL; | ||
1485 | /* Set up Src MAC */ | 1451 | /* Set up Src MAC */ |
1486 | if (compare_ether_addr(old_smac, pkt_dev->src_mac)) | 1452 | memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN); |
1487 | memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); | ||
1488 | 1453 | ||
1489 | sprintf(pg_result, "OK: srcmac"); | 1454 | sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); |
1490 | return count; | 1455 | return count; |
1491 | } | 1456 | } |
1492 | 1457 | ||
@@ -1712,6 +1677,18 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1712 | return count; | 1677 | return count; |
1713 | } | 1678 | } |
1714 | 1679 | ||
1680 | if (!strcmp(name, "skb_priority")) { | ||
1681 | len = num_arg(&user_buffer[i], 9, &value); | ||
1682 | if (len < 0) | ||
1683 | return len; | ||
1684 | |||
1685 | i += len; | ||
1686 | pkt_dev->skb_priority = value; | ||
1687 | sprintf(pg_result, "OK: skb_priority=%i", | ||
1688 | pkt_dev->skb_priority); | ||
1689 | return count; | ||
1690 | } | ||
1691 | |||
1715 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); | 1692 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); |
1716 | return -EINVAL; | 1693 | return -EINVAL; |
1717 | } | 1694 | } |
@@ -1766,7 +1743,7 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1766 | { | 1743 | { |
1767 | struct seq_file *seq = file->private_data; | 1744 | struct seq_file *seq = file->private_data; |
1768 | struct pktgen_thread *t = seq->private; | 1745 | struct pktgen_thread *t = seq->private; |
1769 | int i = 0, max, len, ret; | 1746 | int i, max, len, ret; |
1770 | char name[40]; | 1747 | char name[40]; |
1771 | char *pg_result; | 1748 | char *pg_result; |
1772 | 1749 | ||
@@ -1775,12 +1752,12 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1775 | return -EINVAL; | 1752 | return -EINVAL; |
1776 | } | 1753 | } |
1777 | 1754 | ||
1778 | max = count - i; | 1755 | max = count; |
1779 | len = count_trail_chars(&user_buffer[i], max); | 1756 | len = count_trail_chars(user_buffer, max); |
1780 | if (len < 0) | 1757 | if (len < 0) |
1781 | return len; | 1758 | return len; |
1782 | 1759 | ||
1783 | i += len; | 1760 | i = len; |
1784 | 1761 | ||
1785 | /* Read variable name */ | 1762 | /* Read variable name */ |
1786 | 1763 | ||
@@ -1977,7 +1954,7 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, | |||
1977 | const char *ifname) | 1954 | const char *ifname) |
1978 | { | 1955 | { |
1979 | char b[IFNAMSIZ+5]; | 1956 | char b[IFNAMSIZ+5]; |
1980 | int i = 0; | 1957 | int i; |
1981 | 1958 | ||
1982 | for (i = 0; ifname[i] != '@'; i++) { | 1959 | for (i = 0; ifname[i] != '@'; i++) { |
1983 | if (i == IFNAMSIZ) | 1960 | if (i == IFNAMSIZ) |
@@ -2491,7 +2468,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | |||
2491 | { | 2468 | { |
2492 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; | 2469 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; |
2493 | int err = 0; | 2470 | int err = 0; |
2494 | struct iphdr *iph; | ||
2495 | 2471 | ||
2496 | if (!x) | 2472 | if (!x) |
2497 | return 0; | 2473 | return 0; |
@@ -2501,7 +2477,6 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | |||
2501 | return 0; | 2477 | return 0; |
2502 | 2478 | ||
2503 | spin_lock(&x->lock); | 2479 | spin_lock(&x->lock); |
2504 | iph = ip_hdr(skb); | ||
2505 | 2480 | ||
2506 | err = x->outer_mode->output(x, skb); | 2481 | err = x->outer_mode->output(x, skb); |
2507 | if (err) | 2482 | if (err) |
@@ -2521,8 +2496,8 @@ static void free_SAs(struct pktgen_dev *pkt_dev) | |||
2521 | { | 2496 | { |
2522 | if (pkt_dev->cflows) { | 2497 | if (pkt_dev->cflows) { |
2523 | /* let go of the SAs if we have them */ | 2498 | /* let go of the SAs if we have them */ |
2524 | int i = 0; | 2499 | int i; |
2525 | for (; i < pkt_dev->cflows; i++) { | 2500 | for (i = 0; i < pkt_dev->cflows; i++) { |
2526 | struct xfrm_state *x = pkt_dev->flows[i].x; | 2501 | struct xfrm_state *x = pkt_dev->flows[i].x; |
2527 | if (x) { | 2502 | if (x) { |
2528 | xfrm_state_put(x); | 2503 | xfrm_state_put(x); |
@@ -2587,6 +2562,72 @@ static inline __be16 build_tci(unsigned int id, unsigned int cfi, | |||
2587 | return htons(id | (cfi << 12) | (prio << 13)); | 2562 | return htons(id | (cfi << 12) | (prio << 13)); |
2588 | } | 2563 | } |
2589 | 2564 | ||
2565 | static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, | ||
2566 | int datalen) | ||
2567 | { | ||
2568 | struct timeval timestamp; | ||
2569 | struct pktgen_hdr *pgh; | ||
2570 | |||
2571 | pgh = (struct pktgen_hdr *)skb_put(skb, sizeof(*pgh)); | ||
2572 | datalen -= sizeof(*pgh); | ||
2573 | |||
2574 | if (pkt_dev->nfrags <= 0) { | ||
2575 | memset(skb_put(skb, datalen), 0, datalen); | ||
2576 | } else { | ||
2577 | int frags = pkt_dev->nfrags; | ||
2578 | int i, len; | ||
2579 | int frag_len; | ||
2580 | |||
2581 | |||
2582 | if (frags > MAX_SKB_FRAGS) | ||
2583 | frags = MAX_SKB_FRAGS; | ||
2584 | len = datalen - frags * PAGE_SIZE; | ||
2585 | if (len > 0) { | ||
2586 | memset(skb_put(skb, len), 0, len); | ||
2587 | datalen = frags * PAGE_SIZE; | ||
2588 | } | ||
2589 | |||
2590 | i = 0; | ||
2591 | frag_len = (datalen/frags) < PAGE_SIZE ? | ||
2592 | (datalen/frags) : PAGE_SIZE; | ||
2593 | while (datalen > 0) { | ||
2594 | if (unlikely(!pkt_dev->page)) { | ||
2595 | int node = numa_node_id(); | ||
2596 | |||
2597 | if (pkt_dev->node >= 0 && (pkt_dev->flags & F_NODE)) | ||
2598 | node = pkt_dev->node; | ||
2599 | pkt_dev->page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); | ||
2600 | if (!pkt_dev->page) | ||
2601 | break; | ||
2602 | } | ||
2603 | skb_shinfo(skb)->frags[i].page = pkt_dev->page; | ||
2604 | get_page(pkt_dev->page); | ||
2605 | skb_shinfo(skb)->frags[i].page_offset = 0; | ||
2606 | /*last fragment, fill rest of data*/ | ||
2607 | if (i == (frags - 1)) | ||
2608 | skb_shinfo(skb)->frags[i].size = | ||
2609 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); | ||
2610 | else | ||
2611 | skb_shinfo(skb)->frags[i].size = frag_len; | ||
2612 | datalen -= skb_shinfo(skb)->frags[i].size; | ||
2613 | skb->len += skb_shinfo(skb)->frags[i].size; | ||
2614 | skb->data_len += skb_shinfo(skb)->frags[i].size; | ||
2615 | i++; | ||
2616 | skb_shinfo(skb)->nr_frags = i; | ||
2617 | } | ||
2618 | } | ||
2619 | |||
2620 | /* Stamp the time, and sequence number, | ||
2621 | * convert them to network byte order | ||
2622 | */ | ||
2623 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | ||
2624 | pgh->seq_num = htonl(pkt_dev->seq_num); | ||
2625 | |||
2626 | do_gettimeofday(×tamp); | ||
2627 | pgh->tv_sec = htonl(timestamp.tv_sec); | ||
2628 | pgh->tv_usec = htonl(timestamp.tv_usec); | ||
2629 | } | ||
2630 | |||
2590 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | 2631 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, |
2591 | struct pktgen_dev *pkt_dev) | 2632 | struct pktgen_dev *pkt_dev) |
2592 | { | 2633 | { |
@@ -2595,7 +2636,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2595 | struct udphdr *udph; | 2636 | struct udphdr *udph; |
2596 | int datalen, iplen; | 2637 | int datalen, iplen; |
2597 | struct iphdr *iph; | 2638 | struct iphdr *iph; |
2598 | struct pktgen_hdr *pgh = NULL; | ||
2599 | __be16 protocol = htons(ETH_P_IP); | 2639 | __be16 protocol = htons(ETH_P_IP); |
2600 | __be32 *mpls; | 2640 | __be32 *mpls; |
2601 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | 2641 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ |
@@ -2613,8 +2653,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2613 | /* Update any of the values, used when we're incrementing various | 2653 | /* Update any of the values, used when we're incrementing various |
2614 | * fields. | 2654 | * fields. |
2615 | */ | 2655 | */ |
2616 | queue_map = pkt_dev->cur_queue_map; | ||
2617 | mod_cur_headers(pkt_dev); | 2656 | mod_cur_headers(pkt_dev); |
2657 | queue_map = pkt_dev->cur_queue_map; | ||
2618 | 2658 | ||
2619 | datalen = (odev->hard_header_len + 16) & ~0xf; | 2659 | datalen = (odev->hard_header_len + 16) & ~0xf; |
2620 | 2660 | ||
@@ -2642,6 +2682,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2642 | sprintf(pkt_dev->result, "No memory"); | 2682 | sprintf(pkt_dev->result, "No memory"); |
2643 | return NULL; | 2683 | return NULL; |
2644 | } | 2684 | } |
2685 | prefetchw(skb->data); | ||
2645 | 2686 | ||
2646 | skb_reserve(skb, datalen); | 2687 | skb_reserve(skb, datalen); |
2647 | 2688 | ||
@@ -2672,6 +2713,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2672 | skb->transport_header = skb->network_header + sizeof(struct iphdr); | 2713 | skb->transport_header = skb->network_header + sizeof(struct iphdr); |
2673 | skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); | 2714 | skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); |
2674 | skb_set_queue_mapping(skb, queue_map); | 2715 | skb_set_queue_mapping(skb, queue_map); |
2716 | skb->priority = pkt_dev->skb_priority; | ||
2717 | |||
2675 | iph = ip_hdr(skb); | 2718 | iph = ip_hdr(skb); |
2676 | udph = udp_hdr(skb); | 2719 | udph = udp_hdr(skb); |
2677 | 2720 | ||
@@ -2708,76 +2751,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2708 | pkt_dev->pkt_overhead); | 2751 | pkt_dev->pkt_overhead); |
2709 | skb->dev = odev; | 2752 | skb->dev = odev; |
2710 | skb->pkt_type = PACKET_HOST; | 2753 | skb->pkt_type = PACKET_HOST; |
2711 | 2754 | pktgen_finalize_skb(pkt_dev, skb, datalen); | |
2712 | if (pkt_dev->nfrags <= 0) { | ||
2713 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | ||
2714 | memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); | ||
2715 | } else { | ||
2716 | int frags = pkt_dev->nfrags; | ||
2717 | int i, len; | ||
2718 | |||
2719 | pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); | ||
2720 | |||
2721 | if (frags > MAX_SKB_FRAGS) | ||
2722 | frags = MAX_SKB_FRAGS; | ||
2723 | if (datalen > frags * PAGE_SIZE) { | ||
2724 | len = datalen - frags * PAGE_SIZE; | ||
2725 | memset(skb_put(skb, len), 0, len); | ||
2726 | datalen = frags * PAGE_SIZE; | ||
2727 | } | ||
2728 | |||
2729 | i = 0; | ||
2730 | while (datalen > 0) { | ||
2731 | struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); | ||
2732 | skb_shinfo(skb)->frags[i].page = page; | ||
2733 | skb_shinfo(skb)->frags[i].page_offset = 0; | ||
2734 | skb_shinfo(skb)->frags[i].size = | ||
2735 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); | ||
2736 | datalen -= skb_shinfo(skb)->frags[i].size; | ||
2737 | skb->len += skb_shinfo(skb)->frags[i].size; | ||
2738 | skb->data_len += skb_shinfo(skb)->frags[i].size; | ||
2739 | i++; | ||
2740 | skb_shinfo(skb)->nr_frags = i; | ||
2741 | } | ||
2742 | |||
2743 | while (i < frags) { | ||
2744 | int rem; | ||
2745 | |||
2746 | if (i == 0) | ||
2747 | break; | ||
2748 | |||
2749 | rem = skb_shinfo(skb)->frags[i - 1].size / 2; | ||
2750 | if (rem == 0) | ||
2751 | break; | ||
2752 | |||
2753 | skb_shinfo(skb)->frags[i - 1].size -= rem; | ||
2754 | |||
2755 | skb_shinfo(skb)->frags[i] = | ||
2756 | skb_shinfo(skb)->frags[i - 1]; | ||
2757 | get_page(skb_shinfo(skb)->frags[i].page); | ||
2758 | skb_shinfo(skb)->frags[i].page = | ||
2759 | skb_shinfo(skb)->frags[i - 1].page; | ||
2760 | skb_shinfo(skb)->frags[i].page_offset += | ||
2761 | skb_shinfo(skb)->frags[i - 1].size; | ||
2762 | skb_shinfo(skb)->frags[i].size = rem; | ||
2763 | i++; | ||
2764 | skb_shinfo(skb)->nr_frags = i; | ||
2765 | } | ||
2766 | } | ||
2767 | |||
2768 | /* Stamp the time, and sequence number, | ||
2769 | * convert them to network byte order | ||
2770 | */ | ||
2771 | if (pgh) { | ||
2772 | struct timeval timestamp; | ||
2773 | |||
2774 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | ||
2775 | pgh->seq_num = htonl(pkt_dev->seq_num); | ||
2776 | |||
2777 | do_gettimeofday(×tamp); | ||
2778 | pgh->tv_sec = htonl(timestamp.tv_sec); | ||
2779 | pgh->tv_usec = htonl(timestamp.tv_usec); | ||
2780 | } | ||
2781 | 2755 | ||
2782 | #ifdef CONFIG_XFRM | 2756 | #ifdef CONFIG_XFRM |
2783 | if (!process_ipsec(pkt_dev, skb, protocol)) | 2757 | if (!process_ipsec(pkt_dev, skb, protocol)) |
@@ -2878,79 +2852,6 @@ static unsigned int scan_ip6(const char *s, char ip[16]) | |||
2878 | return len; | 2852 | return len; |
2879 | } | 2853 | } |
2880 | 2854 | ||
2881 | static char tohex(char hexdigit) | ||
2882 | { | ||
2883 | return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; | ||
2884 | } | ||
2885 | |||
2886 | static int fmt_xlong(char *s, unsigned int i) | ||
2887 | { | ||
2888 | char *bak = s; | ||
2889 | *s = tohex((i >> 12) & 0xf); | ||
2890 | if (s != bak || *s != '0') | ||
2891 | ++s; | ||
2892 | *s = tohex((i >> 8) & 0xf); | ||
2893 | if (s != bak || *s != '0') | ||
2894 | ++s; | ||
2895 | *s = tohex((i >> 4) & 0xf); | ||
2896 | if (s != bak || *s != '0') | ||
2897 | ++s; | ||
2898 | *s = tohex(i & 0xf); | ||
2899 | return s - bak + 1; | ||
2900 | } | ||
2901 | |||
2902 | static unsigned int fmt_ip6(char *s, const char ip[16]) | ||
2903 | { | ||
2904 | unsigned int len; | ||
2905 | unsigned int i; | ||
2906 | unsigned int temp; | ||
2907 | unsigned int compressing; | ||
2908 | int j; | ||
2909 | |||
2910 | len = 0; | ||
2911 | compressing = 0; | ||
2912 | for (j = 0; j < 16; j += 2) { | ||
2913 | |||
2914 | #ifdef V4MAPPEDPREFIX | ||
2915 | if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { | ||
2916 | inet_ntoa_r(*(struct in_addr *)(ip + 12), s); | ||
2917 | temp = strlen(s); | ||
2918 | return len + temp; | ||
2919 | } | ||
2920 | #endif | ||
2921 | temp = ((unsigned long)(unsigned char)ip[j] << 8) + | ||
2922 | (unsigned long)(unsigned char)ip[j + 1]; | ||
2923 | if (temp == 0) { | ||
2924 | if (!compressing) { | ||
2925 | compressing = 1; | ||
2926 | if (j == 0) { | ||
2927 | *s++ = ':'; | ||
2928 | ++len; | ||
2929 | } | ||
2930 | } | ||
2931 | } else { | ||
2932 | if (compressing) { | ||
2933 | compressing = 0; | ||
2934 | *s++ = ':'; | ||
2935 | ++len; | ||
2936 | } | ||
2937 | i = fmt_xlong(s, temp); | ||
2938 | len += i; | ||
2939 | s += i; | ||
2940 | if (j < 14) { | ||
2941 | *s++ = ':'; | ||
2942 | ++len; | ||
2943 | } | ||
2944 | } | ||
2945 | } | ||
2946 | if (compressing) { | ||
2947 | *s++ = ':'; | ||
2948 | ++len; | ||
2949 | } | ||
2950 | *s = 0; | ||
2951 | return len; | ||
2952 | } | ||
2953 | |||
2954 | static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | 2855 | static struct sk_buff *fill_packet_ipv6(struct net_device *odev, |
2955 | struct pktgen_dev *pkt_dev) | 2856 | struct pktgen_dev *pkt_dev) |
2956 | { | 2857 | { |
@@ -2959,7 +2860,6 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2959 | struct udphdr *udph; | 2860 | struct udphdr *udph; |
2960 | int datalen; | 2861 | int datalen; |
2961 | struct ipv6hdr *iph; | 2862 | struct ipv6hdr *iph; |
2962 | struct pktgen_hdr *pgh = NULL; | ||
2963 | __be16 protocol = htons(ETH_P_IPV6); | 2863 | __be16 protocol = htons(ETH_P_IPV6); |
2964 | __be32 *mpls; | 2864 | __be32 *mpls; |
2965 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ | 2865 | __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ |
@@ -2977,8 +2877,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2977 | /* Update any of the values, used when we're incrementing various | 2877 | /* Update any of the values, used when we're incrementing various |
2978 | * fields. | 2878 | * fields. |
2979 | */ | 2879 | */ |
2980 | queue_map = pkt_dev->cur_queue_map; | ||
2981 | mod_cur_headers(pkt_dev); | 2880 | mod_cur_headers(pkt_dev); |
2881 | queue_map = pkt_dev->cur_queue_map; | ||
2982 | 2882 | ||
2983 | skb = __netdev_alloc_skb(odev, | 2883 | skb = __netdev_alloc_skb(odev, |
2984 | pkt_dev->cur_pkt_size + 64 | 2884 | pkt_dev->cur_pkt_size + 64 |
@@ -2987,6 +2887,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2987 | sprintf(pkt_dev->result, "No memory"); | 2887 | sprintf(pkt_dev->result, "No memory"); |
2988 | return NULL; | 2888 | return NULL; |
2989 | } | 2889 | } |
2890 | prefetchw(skb->data); | ||
2990 | 2891 | ||
2991 | skb_reserve(skb, 16); | 2892 | skb_reserve(skb, 16); |
2992 | 2893 | ||
@@ -3017,6 +2918,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
3017 | skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); | 2918 | skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); |
3018 | skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); | 2919 | skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); |
3019 | skb_set_queue_mapping(skb, queue_map); | 2920 | skb_set_queue_mapping(skb, queue_map); |
2921 | skb->priority = pkt_dev->skb_priority; | ||
3020 | iph = ipv6_hdr(skb); | 2922 | iph = ipv6_hdr(skb); |
3021 | udph = udp_hdr(skb); | 2923 | udph = udp_hdr(skb); |
3022 | 2924 | ||
@@ -3060,75 +2962,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
3060 | skb->dev = odev; | 2962 | skb->dev = odev; |
3061 | skb->pkt_type = PACKET_HOST; | 2963 | skb->pkt_type = PACKET_HOST; |
3062 | 2964 | ||
3063 | if (pkt_dev->nfrags <= 0) | 2965 | pktgen_finalize_skb(pkt_dev, skb, datalen); |
3064 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | ||
3065 | else { | ||
3066 | int frags = pkt_dev->nfrags; | ||
3067 | int i; | ||
3068 | |||
3069 | pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); | ||
3070 | |||
3071 | if (frags > MAX_SKB_FRAGS) | ||
3072 | frags = MAX_SKB_FRAGS; | ||
3073 | if (datalen > frags * PAGE_SIZE) { | ||
3074 | skb_put(skb, datalen - frags * PAGE_SIZE); | ||
3075 | datalen = frags * PAGE_SIZE; | ||
3076 | } | ||
3077 | |||
3078 | i = 0; | ||
3079 | while (datalen > 0) { | ||
3080 | struct page *page = alloc_pages(GFP_KERNEL, 0); | ||
3081 | skb_shinfo(skb)->frags[i].page = page; | ||
3082 | skb_shinfo(skb)->frags[i].page_offset = 0; | ||
3083 | skb_shinfo(skb)->frags[i].size = | ||
3084 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); | ||
3085 | datalen -= skb_shinfo(skb)->frags[i].size; | ||
3086 | skb->len += skb_shinfo(skb)->frags[i].size; | ||
3087 | skb->data_len += skb_shinfo(skb)->frags[i].size; | ||
3088 | i++; | ||
3089 | skb_shinfo(skb)->nr_frags = i; | ||
3090 | } | ||
3091 | |||
3092 | while (i < frags) { | ||
3093 | int rem; | ||
3094 | |||
3095 | if (i == 0) | ||
3096 | break; | ||
3097 | |||
3098 | rem = skb_shinfo(skb)->frags[i - 1].size / 2; | ||
3099 | if (rem == 0) | ||
3100 | break; | ||
3101 | |||
3102 | skb_shinfo(skb)->frags[i - 1].size -= rem; | ||
3103 | |||
3104 | skb_shinfo(skb)->frags[i] = | ||
3105 | skb_shinfo(skb)->frags[i - 1]; | ||
3106 | get_page(skb_shinfo(skb)->frags[i].page); | ||
3107 | skb_shinfo(skb)->frags[i].page = | ||
3108 | skb_shinfo(skb)->frags[i - 1].page; | ||
3109 | skb_shinfo(skb)->frags[i].page_offset += | ||
3110 | skb_shinfo(skb)->frags[i - 1].size; | ||
3111 | skb_shinfo(skb)->frags[i].size = rem; | ||
3112 | i++; | ||
3113 | skb_shinfo(skb)->nr_frags = i; | ||
3114 | } | ||
3115 | } | ||
3116 | |||
3117 | /* Stamp the time, and sequence number, | ||
3118 | * convert them to network byte order | ||
3119 | * should we update cloned packets too ? | ||
3120 | */ | ||
3121 | if (pgh) { | ||
3122 | struct timeval timestamp; | ||
3123 | |||
3124 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | ||
3125 | pgh->seq_num = htonl(pkt_dev->seq_num); | ||
3126 | |||
3127 | do_gettimeofday(×tamp); | ||
3128 | pgh->tv_sec = htonl(timestamp.tv_sec); | ||
3129 | pgh->tv_usec = htonl(timestamp.tv_usec); | ||
3130 | } | ||
3131 | /* pkt_dev->seq_num++; FF: you really mean this? */ | ||
3132 | 2966 | ||
3133 | return skb; | 2967 | return skb; |
3134 | } | 2968 | } |
@@ -3298,7 +3132,7 @@ static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) | |||
3298 | pkt_dev->started_at); | 3132 | pkt_dev->started_at); |
3299 | ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); | 3133 | ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); |
3300 | 3134 | ||
3301 | p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", | 3135 | p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", |
3302 | (unsigned long long)ktime_to_us(elapsed), | 3136 | (unsigned long long)ktime_to_us(elapsed), |
3303 | (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), | 3137 | (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), |
3304 | (unsigned long long)ktime_to_us(idle), | 3138 | (unsigned long long)ktime_to_us(idle), |
@@ -3432,11 +3266,6 @@ static void pktgen_rem_thread(struct pktgen_thread *t) | |||
3432 | 3266 | ||
3433 | remove_proc_entry(t->tsk->comm, pg_proc_dir); | 3267 | remove_proc_entry(t->tsk->comm, pg_proc_dir); |
3434 | 3268 | ||
3435 | mutex_lock(&pktgen_thread_lock); | ||
3436 | |||
3437 | list_del(&t->th_list); | ||
3438 | |||
3439 | mutex_unlock(&pktgen_thread_lock); | ||
3440 | } | 3269 | } |
3441 | 3270 | ||
3442 | static void pktgen_resched(struct pktgen_dev *pkt_dev) | 3271 | static void pktgen_resched(struct pktgen_dev *pkt_dev) |
@@ -3511,7 +3340,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
3511 | 3340 | ||
3512 | __netif_tx_lock_bh(txq); | 3341 | __netif_tx_lock_bh(txq); |
3513 | 3342 | ||
3514 | if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) { | 3343 | if (unlikely(netif_tx_queue_frozen_or_stopped(txq))) { |
3515 | ret = NETDEV_TX_BUSY; | 3344 | ret = NETDEV_TX_BUSY; |
3516 | pkt_dev->last_ok = 0; | 3345 | pkt_dev->last_ok = 0; |
3517 | goto unlock; | 3346 | goto unlock; |
@@ -3535,8 +3364,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
3535 | break; | 3364 | break; |
3536 | default: /* Drivers are not supposed to return other values! */ | 3365 | default: /* Drivers are not supposed to return other values! */ |
3537 | if (net_ratelimit()) | 3366 | if (net_ratelimit()) |
3538 | pr_info("pktgen: %s xmit error: %d\n", | 3367 | pr_info("%s xmit error: %d\n", pkt_dev->odevname, ret); |
3539 | pkt_dev->odevname, ret); | ||
3540 | pkt_dev->errors++; | 3368 | pkt_dev->errors++; |
3541 | /* fallthru */ | 3369 | /* fallthru */ |
3542 | case NETDEV_TX_LOCKED: | 3370 | case NETDEV_TX_LOCKED: |
@@ -3583,6 +3411,8 @@ static int pktgen_thread_worker(void *arg) | |||
3583 | pkt_dev = next_to_run(t); | 3411 | pkt_dev = next_to_run(t); |
3584 | 3412 | ||
3585 | if (unlikely(!pkt_dev && t->control == 0)) { | 3413 | if (unlikely(!pkt_dev && t->control == 0)) { |
3414 | if (pktgen_exiting) | ||
3415 | break; | ||
3586 | wait_event_interruptible_timeout(t->queue, | 3416 | wait_event_interruptible_timeout(t->queue, |
3587 | t->control != 0, | 3417 | t->control != 0, |
3588 | HZ/10); | 3418 | HZ/10); |
@@ -3635,6 +3465,13 @@ static int pktgen_thread_worker(void *arg) | |||
3635 | pr_debug("%s removing thread\n", t->tsk->comm); | 3465 | pr_debug("%s removing thread\n", t->tsk->comm); |
3636 | pktgen_rem_thread(t); | 3466 | pktgen_rem_thread(t); |
3637 | 3467 | ||
3468 | /* Wait for kthread_stop */ | ||
3469 | while (!kthread_should_stop()) { | ||
3470 | set_current_state(TASK_INTERRUPTIBLE); | ||
3471 | schedule(); | ||
3472 | } | ||
3473 | __set_current_state(TASK_RUNNING); | ||
3474 | |||
3638 | return 0; | 3475 | return 0; |
3639 | } | 3476 | } |
3640 | 3477 | ||
@@ -3707,13 +3544,12 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3707 | return -ENOMEM; | 3544 | return -ENOMEM; |
3708 | 3545 | ||
3709 | strcpy(pkt_dev->odevname, ifname); | 3546 | strcpy(pkt_dev->odevname, ifname); |
3710 | pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), | 3547 | pkt_dev->flows = vzalloc_node(MAX_CFLOWS * sizeof(struct flow_state), |
3711 | node); | 3548 | node); |
3712 | if (pkt_dev->flows == NULL) { | 3549 | if (pkt_dev->flows == NULL) { |
3713 | kfree(pkt_dev); | 3550 | kfree(pkt_dev); |
3714 | return -ENOMEM; | 3551 | return -ENOMEM; |
3715 | } | 3552 | } |
3716 | memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); | ||
3717 | 3553 | ||
3718 | pkt_dev->removal_mark = 0; | 3554 | pkt_dev->removal_mark = 0; |
3719 | pkt_dev->min_pkt_size = ETH_ZLEN; | 3555 | pkt_dev->min_pkt_size = ETH_ZLEN; |
@@ -3786,7 +3622,10 @@ static int __init pktgen_create_thread(int cpu) | |||
3786 | list_add_tail(&t->th_list, &pktgen_threads); | 3622 | list_add_tail(&t->th_list, &pktgen_threads); |
3787 | init_completion(&t->start_done); | 3623 | init_completion(&t->start_done); |
3788 | 3624 | ||
3789 | p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); | 3625 | p = kthread_create_on_node(pktgen_thread_worker, |
3626 | t, | ||
3627 | cpu_to_node(cpu), | ||
3628 | "kpktgend_%d", cpu); | ||
3790 | if (IS_ERR(p)) { | 3629 | if (IS_ERR(p)) { |
3791 | pr_err("kernel_thread() failed for cpu %d\n", t->cpu); | 3630 | pr_err("kernel_thread() failed for cpu %d\n", t->cpu); |
3792 | list_del(&t->th_list); | 3631 | list_del(&t->th_list); |
@@ -3858,6 +3697,8 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
3858 | free_SAs(pkt_dev); | 3697 | free_SAs(pkt_dev); |
3859 | #endif | 3698 | #endif |
3860 | vfree(pkt_dev->flows); | 3699 | vfree(pkt_dev->flows); |
3700 | if (pkt_dev->page) | ||
3701 | put_page(pkt_dev->page); | ||
3861 | kfree(pkt_dev); | 3702 | kfree(pkt_dev); |
3862 | return 0; | 3703 | return 0; |
3863 | } | 3704 | } |
@@ -3866,6 +3707,7 @@ static int __init pg_init(void) | |||
3866 | { | 3707 | { |
3867 | int cpu; | 3708 | int cpu; |
3868 | struct proc_dir_entry *pe; | 3709 | struct proc_dir_entry *pe; |
3710 | int ret = 0; | ||
3869 | 3711 | ||
3870 | pr_info("%s", version); | 3712 | pr_info("%s", version); |
3871 | 3713 | ||
@@ -3876,11 +3718,10 @@ static int __init pg_init(void) | |||
3876 | pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); | 3718 | pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); |
3877 | if (pe == NULL) { | 3719 | if (pe == NULL) { |
3878 | pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); | 3720 | pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); |
3879 | proc_net_remove(&init_net, PG_PROC_DIR); | 3721 | ret = -EINVAL; |
3880 | return -EINVAL; | 3722 | goto remove_dir; |
3881 | } | 3723 | } |
3882 | 3724 | ||
3883 | /* Register us to receive netdevice events */ | ||
3884 | register_netdevice_notifier(&pktgen_notifier_block); | 3725 | register_netdevice_notifier(&pktgen_notifier_block); |
3885 | 3726 | ||
3886 | for_each_online_cpu(cpu) { | 3727 | for_each_online_cpu(cpu) { |
@@ -3894,23 +3735,27 @@ static int __init pg_init(void) | |||
3894 | 3735 | ||
3895 | if (list_empty(&pktgen_threads)) { | 3736 | if (list_empty(&pktgen_threads)) { |
3896 | pr_err("ERROR: Initialization failed for all threads\n"); | 3737 | pr_err("ERROR: Initialization failed for all threads\n"); |
3897 | unregister_netdevice_notifier(&pktgen_notifier_block); | 3738 | ret = -ENODEV; |
3898 | remove_proc_entry(PGCTRL, pg_proc_dir); | 3739 | goto unregister; |
3899 | proc_net_remove(&init_net, PG_PROC_DIR); | ||
3900 | return -ENODEV; | ||
3901 | } | 3740 | } |
3902 | 3741 | ||
3903 | return 0; | 3742 | return 0; |
3743 | |||
3744 | unregister: | ||
3745 | unregister_netdevice_notifier(&pktgen_notifier_block); | ||
3746 | remove_proc_entry(PGCTRL, pg_proc_dir); | ||
3747 | remove_dir: | ||
3748 | proc_net_remove(&init_net, PG_PROC_DIR); | ||
3749 | return ret; | ||
3904 | } | 3750 | } |
3905 | 3751 | ||
3906 | static void __exit pg_cleanup(void) | 3752 | static void __exit pg_cleanup(void) |
3907 | { | 3753 | { |
3908 | struct pktgen_thread *t; | 3754 | struct pktgen_thread *t; |
3909 | struct list_head *q, *n; | 3755 | struct list_head *q, *n; |
3910 | wait_queue_head_t queue; | ||
3911 | init_waitqueue_head(&queue); | ||
3912 | 3756 | ||
3913 | /* Stop all interfaces & threads */ | 3757 | /* Stop all interfaces & threads */ |
3758 | pktgen_exiting = true; | ||
3914 | 3759 | ||
3915 | list_for_each_safe(q, n, &pktgen_threads) { | 3760 | list_for_each_safe(q, n, &pktgen_threads) { |
3916 | t = list_entry(q, struct pktgen_thread, th_list); | 3761 | t = list_entry(q, struct pktgen_thread, th_list); |