11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Authors: 31da177e4SLinus Torvalds * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> 41da177e4SLinus Torvalds * Uppsala University and 51da177e4SLinus Torvalds * Swedish University of Agricultural Sciences 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 81da177e4SLinus Torvalds * Ben Greear <greearb@candelatech.com> 996de0e25SJan Engelhardt * Jens Låås <jens.laas@data.slu.se> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 121da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 131da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 141da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * A tool for loading the network with preconfigurated packets. 181da177e4SLinus Torvalds * The tool is implemented as a linux module. Parameters are output 191da177e4SLinus Torvalds * device, delay (to hard_xmit), number of packets, and whether 201da177e4SLinus Torvalds * to use multiple SKBs or just the same one. 211da177e4SLinus Torvalds * pktgen uses the installed interface's output routine. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * Additional hacking by: 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * Jens.Laas@data.slu.se 261da177e4SLinus Torvalds * Improved by ANK. 010120. 271da177e4SLinus Torvalds * Improved by ANK even more. 010212. 281da177e4SLinus Torvalds * MAC address typo fixed. 010417 --ro 291da177e4SLinus Torvalds * Integrated. 020301 --DaveM 301da177e4SLinus Torvalds * Added multiskb option 020301 --DaveM 311da177e4SLinus Torvalds * Scaling of results. 020417--sigurdur@linpro.no 321da177e4SLinus Torvalds * Significant re-work of the module: 331da177e4SLinus Torvalds * * Convert to threaded model to more efficiently be able to transmit 341da177e4SLinus Torvalds * and receive on multiple interfaces at once. 351da177e4SLinus Torvalds * * Converted many counters to __u64 to allow longer runs. 361da177e4SLinus Torvalds * * Allow configuration of ranges, like min/max IP address, MACs, 371da177e4SLinus Torvalds * and UDP-ports, for both source and destination, and can 381da177e4SLinus Torvalds * set to use a random distribution or sequentially walk the range. 391da177e4SLinus Torvalds * * Can now change most values after starting. 401da177e4SLinus Torvalds * * Place 12-byte packet in UDP payload with magic number, 411da177e4SLinus Torvalds * sequence number, and timestamp. 421da177e4SLinus Torvalds * * Add receiver code that detects dropped pkts, re-ordered pkts, and 431da177e4SLinus Torvalds * latencies (with micro-second) precision. 441da177e4SLinus Torvalds * * Add IOCTL interface to easily get counters & configuration. 451da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 461da177e4SLinus Torvalds * 471da177e4SLinus Torvalds * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 481da177e4SLinus Torvalds * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 491da177e4SLinus Torvalds * as a "fastpath" with a configurable number of clones after alloc's. 501da177e4SLinus Torvalds * clone_skb=0 means all packets are allocated this also means ranges time 511da177e4SLinus Torvalds * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 521da177e4SLinus Torvalds * clones. 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * Also moved to /proc/net/pktgen/ 551da177e4SLinus Torvalds * --ro 561da177e4SLinus Torvalds * 571da177e4SLinus Torvalds * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever 581da177e4SLinus Torvalds * mistakes. Also merged in DaveM's patch in the -pre6 patch. 591da177e4SLinus Torvalds * --Ben Greear <greearb@candelatech.com> 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br) 621da177e4SLinus Torvalds * 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * 021124 Finished major redesign and rewrite for new functionality. 651da177e4SLinus Torvalds * See Documentation/networking/pktgen.txt for how to use this. 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * The new operation: 681da177e4SLinus Torvalds * For each CPU one thread/process is created at start. This process checks 691da177e4SLinus Torvalds * for running devices in the if_list and sends packets until count is 0 it 701da177e4SLinus Torvalds * also the thread checks the thread->control which is used for inter-process 711da177e4SLinus Torvalds * communication. controlling process "posts" operations to the threads this 721da177e4SLinus Torvalds * way. The if_lock should be possible to remove when add/rem_device is merged 731da177e4SLinus Torvalds * into this too. 741da177e4SLinus Torvalds * 751da177e4SLinus Torvalds * By design there should only be *one* "controlling" process. In practice 761da177e4SLinus Torvalds * multiple write accesses gives unpredictable result. Understood by "write" 771da177e4SLinus Torvalds * to /proc gives result code thats should be read be the "writer". 78b4099fabSStephen Hemminger * For practical use this should be no problem. 791da177e4SLinus Torvalds * 801da177e4SLinus Torvalds * Note when adding devices to a specific CPU there good idea to also assign 811da177e4SLinus Torvalds * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 821da177e4SLinus Torvalds * --ro 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Fix refcount off by one if first packet fails, potential null deref, 851da177e4SLinus Torvalds * memleak 030710- KJP 861da177e4SLinus Torvalds * 871da177e4SLinus Torvalds * First "ranges" functionality for ipv6 030726 --ro 881da177e4SLinus Torvalds * 891da177e4SLinus Torvalds * Included flow support. 030802 ANK. 901da177e4SLinus Torvalds * 911da177e4SLinus Torvalds * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org> 921da177e4SLinus Torvalds * 931da177e4SLinus Torvalds * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419 941da177e4SLinus Torvalds * ia64 compilation fix from Aron Griffis <aron@hp.com> 040604 951da177e4SLinus Torvalds * 961da177e4SLinus Torvalds * New xmit() return, do_div and misc clean up by Stephen Hemminger 971da177e4SLinus Torvalds * <shemminger@osdl.org> 040923 981da177e4SLinus Torvalds * 99b4099fabSStephen Hemminger * Randy Dunlap fixed u64 printk compiler waring 1001da177e4SLinus Torvalds * 1011da177e4SLinus Torvalds * Remove FCS from BW calculation. Lennert Buytenhek <buytenh@wantstofly.org> 1021da177e4SLinus Torvalds * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213 1031da177e4SLinus Torvalds * 1041da177e4SLinus Torvalds * Corrections from Nikolai Malykh (nmalykh@bilim.com) 1051da177e4SLinus Torvalds * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 1061da177e4SLinus Torvalds * 1071da177e4SLinus Torvalds * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 1081da177e4SLinus Torvalds * 050103 109ca6549afSSteven Whitehouse * 110ca6549afSSteven Whitehouse * MPLS support by Steven Whitehouse <steve@chygwyn.com> 111ca6549afSSteven Whitehouse * 11234954ddcSFrancesco Fondelli * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com> 11334954ddcSFrancesco Fondelli * 114ce5d0b47SAdit Ranadive * Fixed src_mac command to set source mac of packet to value specified in 115ce5d0b47SAdit Ranadive * command by Adit Ranadive <adit.262@gmail.com> 116ce5d0b47SAdit Ranadive * 1171da177e4SLinus Torvalds */ 118f9467eaeSJoe Perches 119f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 120f9467eaeSJoe Perches 1211da177e4SLinus Torvalds #include <linux/sys.h> 1221da177e4SLinus Torvalds #include <linux/types.h> 1231da177e4SLinus Torvalds #include <linux/module.h> 1241da177e4SLinus Torvalds #include <linux/moduleparam.h> 1251da177e4SLinus Torvalds #include <linux/kernel.h> 126222fa076SLuiz Capitulino #include <linux/mutex.h> 1271da177e4SLinus Torvalds #include <linux/sched.h> 1281da177e4SLinus Torvalds #include <linux/slab.h> 1291da177e4SLinus Torvalds #include <linux/vmalloc.h> 1301da177e4SLinus Torvalds #include <linux/unistd.h> 1311da177e4SLinus Torvalds #include <linux/string.h> 1321da177e4SLinus Torvalds #include <linux/ptrace.h> 1331da177e4SLinus Torvalds #include <linux/errno.h> 1341da177e4SLinus Torvalds #include <linux/ioport.h> 1351da177e4SLinus Torvalds #include <linux/interrupt.h> 1364fc268d2SRandy Dunlap #include <linux/capability.h> 1372bc481cfSStephen Hemminger #include <linux/hrtimer.h> 13809fe3ef4SAndrew Morton #include <linux/freezer.h> 1391da177e4SLinus Torvalds #include <linux/delay.h> 1401da177e4SLinus Torvalds #include <linux/timer.h> 141cdcdbe0bSLuiz Capitulino #include <linux/list.h> 1421da177e4SLinus Torvalds #include <linux/init.h> 1431da177e4SLinus Torvalds #include <linux/skbuff.h> 1441da177e4SLinus Torvalds #include <linux/netdevice.h> 1451da177e4SLinus Torvalds #include <linux/inet.h> 1461da177e4SLinus Torvalds #include <linux/inetdevice.h> 1471da177e4SLinus Torvalds #include <linux/rtnetlink.h> 1481da177e4SLinus Torvalds #include <linux/if_arp.h> 14934954ddcSFrancesco Fondelli #include <linux/if_vlan.h> 1501da177e4SLinus Torvalds #include <linux/in.h> 1511da177e4SLinus Torvalds #include <linux/ip.h> 1521da177e4SLinus Torvalds #include <linux/ipv6.h> 1531da177e4SLinus Torvalds #include <linux/udp.h> 1541da177e4SLinus Torvalds #include <linux/proc_fs.h> 155d50a6b56SStephen Hemminger #include <linux/seq_file.h> 1561da177e4SLinus Torvalds #include <linux/wait.h> 157f404e9a6SKris Katterjohn #include <linux/etherdevice.h> 158ee74baa7SDavid S. Miller #include <linux/kthread.h> 159457c4cbcSEric W. Biederman #include <net/net_namespace.h> 1601da177e4SLinus Torvalds #include <net/checksum.h> 1611da177e4SLinus Torvalds #include <net/ipv6.h> 1621da177e4SLinus Torvalds #include <net/addrconf.h> 163a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 164a553e4a6SJamal Hadi Salim #include <net/xfrm.h> 165a553e4a6SJamal Hadi Salim #endif 1661da177e4SLinus Torvalds #include <asm/byteorder.h> 1671da177e4SLinus Torvalds #include <linux/rcupdate.h> 1681977f032SJiri Slaby #include <linux/bitops.h> 16963adc6fbSStephen Hemminger #include <linux/io.h> 17063adc6fbSStephen Hemminger #include <linux/timex.h> 17163adc6fbSStephen Hemminger #include <linux/uaccess.h> 1721da177e4SLinus Torvalds #include <asm/dma.h> 1731da177e4SLinus Torvalds #include <asm/div64.h> /* do_div */ 1741da177e4SLinus Torvalds 17543d28b65SDaniel Turull #define VERSION "2.74" 1761da177e4SLinus Torvalds #define IP_NAME_SZ 32 177ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ 178d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100) 1791da177e4SLinus Torvalds 180f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__); 181f9467eaeSJoe Perches 1821da177e4SLinus Torvalds /* Device flag bits */ 1831da177e4SLinus Torvalds #define F_IPSRC_RND (1<<0) /* IP-Src Random */ 1841da177e4SLinus Torvalds #define F_IPDST_RND (1<<1) /* IP-Dst Random */ 1851da177e4SLinus Torvalds #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ 1861da177e4SLinus Torvalds #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ 1871da177e4SLinus Torvalds #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ 1881da177e4SLinus Torvalds #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ 1891da177e4SLinus Torvalds #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ 1901da177e4SLinus Torvalds #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ 191ca6549afSSteven Whitehouse #define F_MPLS_RND (1<<8) /* Random MPLS labels */ 19234954ddcSFrancesco Fondelli #define F_VID_RND (1<<9) /* Random VLAN ID */ 19334954ddcSFrancesco Fondelli #define F_SVID_RND (1<<10) /* Random SVLAN ID */ 194007a531bSJamal Hadi Salim #define F_FLOW_SEQ (1<<11) /* Sequential flows */ 195a553e4a6SJamal Hadi Salim #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ 19645b270f8SRobert Olsson #define F_QUEUE_MAP_RND (1<<13) /* queue map Random */ 197e6fce5b9SRobert Olsson #define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */ 198e99b99b4SRobert Olsson #define F_NODE (1<<15) /* Node memory alloc*/ 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds /* Thread control flag bits */ 2016b80d6a6SStephen Hemminger #define T_STOP (1<<0) /* Stop run */ 2026b80d6a6SStephen Hemminger #define T_RUN (1<<1) /* Start run */ 2036b80d6a6SStephen Hemminger #define T_REMDEVALL (1<<2) /* Remove all devs */ 2046b80d6a6SStephen Hemminger #define T_REMDEV (1<<3) /* Remove one dev */ 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* If lock -- can be removed after some work */ 2071da177e4SLinus Torvalds #define if_lock(t) spin_lock(&(t->if_lock)); 2081da177e4SLinus Torvalds #define if_unlock(t) spin_unlock(&(t->if_lock)); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */ 2111da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955 212d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen" 213d50a6b56SStephen Hemminger #define PGCTRL "pgctrl" 21463adc6fbSStephen Hemminger static struct proc_dir_entry *pg_proc_dir; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds #define MAX_CFLOWS 65536 2171da177e4SLinus Torvalds 21834954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) 21934954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) 22034954ddcSFrancesco Fondelli 221222f1806SLuiz Capitulino struct flow_state { 222252e3346SAl Viro __be32 cur_daddr; 2231da177e4SLinus Torvalds int count; 224a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 225a553e4a6SJamal Hadi Salim struct xfrm_state *x; 226a553e4a6SJamal Hadi Salim #endif 227007a531bSJamal Hadi Salim __u32 flags; 2281da177e4SLinus Torvalds }; 2291da177e4SLinus Torvalds 230007a531bSJamal Hadi Salim /* flow flag bits */ 231007a531bSJamal Hadi Salim #define F_INIT (1<<0) /* flow has been initialized */ 232007a531bSJamal Hadi Salim 2331da177e4SLinus Torvalds struct pktgen_dev { 2341da177e4SLinus Torvalds /* 2351da177e4SLinus Torvalds * Try to keep frequent/infrequent used vars. separated. 2361da177e4SLinus Torvalds */ 23739df232fSStephen Hemminger struct proc_dir_entry *entry; /* proc file */ 2381da177e4SLinus Torvalds struct pktgen_thread *pg_thread;/* the owner */ 23963adc6fbSStephen Hemminger struct list_head list; /* chaining in the thread's run-queue */ 2401da177e4SLinus Torvalds 24163adc6fbSStephen Hemminger int running; /* if false, the test will stop */ 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* If min != max, then we will either do a linear iteration, or 2441da177e4SLinus Torvalds * we will do a random selection from within the range. 2451da177e4SLinus Torvalds */ 2461da177e4SLinus Torvalds __u32 flags; 24795ed63f7SArthur Kepner int removal_mark; /* non-zero => the device is marked for 24895ed63f7SArthur Kepner * removal by worker thread */ 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds int min_pkt_size; /* = ETH_ZLEN; */ 2511da177e4SLinus Torvalds int max_pkt_size; /* = ETH_ZLEN; */ 25216dab72fSJamal Hadi Salim int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */ 2531da177e4SLinus Torvalds int nfrags; 254fd29cf72SStephen Hemminger u64 delay; /* nano-seconds */ 255fd29cf72SStephen Hemminger 2561da177e4SLinus Torvalds __u64 count; /* Default No packets to send */ 2571da177e4SLinus Torvalds __u64 sofar; /* How many pkts we've sent so far */ 2581da177e4SLinus Torvalds __u64 tx_bytes; /* How many bytes we've transmitted */ 259f466dba1SJohn Fastabend __u64 errors; /* Errors when trying to transmit, */ 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* runtime counters relating to clone_skb */ 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds __u64 allocated_skbs; 2641da177e4SLinus Torvalds __u32 clone_count; 2651da177e4SLinus Torvalds int last_ok; /* Was last skb sent? 26663adc6fbSStephen Hemminger * Or a failed transmit of some sort? 26763adc6fbSStephen Hemminger * This will keep sequence numbers in order 2681da177e4SLinus Torvalds */ 269fd29cf72SStephen Hemminger ktime_t next_tx; 270fd29cf72SStephen Hemminger ktime_t started_at; 271fd29cf72SStephen Hemminger ktime_t stopped_at; 272fd29cf72SStephen Hemminger u64 idle_acc; /* nano-seconds */ 273fd29cf72SStephen Hemminger 2741da177e4SLinus Torvalds __u32 seq_num; 2751da177e4SLinus Torvalds 27663adc6fbSStephen Hemminger int clone_skb; /* 27763adc6fbSStephen Hemminger * Use multiple SKBs during packet gen. 27863adc6fbSStephen Hemminger * If this number is greater than 1, then 27963adc6fbSStephen Hemminger * that many copies of the same packet will be 28063adc6fbSStephen Hemminger * sent before a new packet is allocated. 28163adc6fbSStephen Hemminger * If you want to send 1024 identical packets 28263adc6fbSStephen Hemminger * before creating a new packet, 28363adc6fbSStephen Hemminger * set clone_skb to 1024. 2841da177e4SLinus Torvalds */ 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2871da177e4SLinus Torvalds char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2881da177e4SLinus Torvalds char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2891da177e4SLinus Torvalds char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds struct in6_addr in6_saddr; 2921da177e4SLinus Torvalds struct in6_addr in6_daddr; 2931da177e4SLinus Torvalds struct in6_addr cur_in6_daddr; 2941da177e4SLinus Torvalds struct in6_addr cur_in6_saddr; 2951da177e4SLinus Torvalds /* For ranges */ 2961da177e4SLinus Torvalds struct in6_addr min_in6_daddr; 2971da177e4SLinus Torvalds struct in6_addr max_in6_daddr; 2981da177e4SLinus Torvalds struct in6_addr min_in6_saddr; 2991da177e4SLinus Torvalds struct in6_addr max_in6_saddr; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* If we're doing ranges, random or incremental, then this 3021da177e4SLinus Torvalds * defines the min/max for those ranges. 3031da177e4SLinus Torvalds */ 304252e3346SAl Viro __be32 saddr_min; /* inclusive, source IP address */ 305252e3346SAl Viro __be32 saddr_max; /* exclusive, source IP address */ 306252e3346SAl Viro __be32 daddr_min; /* inclusive, dest IP address */ 307252e3346SAl Viro __be32 daddr_max; /* exclusive, dest IP address */ 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds __u16 udp_src_min; /* inclusive, source UDP port */ 3101da177e4SLinus Torvalds __u16 udp_src_max; /* exclusive, source UDP port */ 3111da177e4SLinus Torvalds __u16 udp_dst_min; /* inclusive, dest UDP port */ 3121da177e4SLinus Torvalds __u16 udp_dst_max; /* exclusive, dest UDP port */ 3131da177e4SLinus Torvalds 3141ca7768cSFrancesco Fondelli /* DSCP + ECN */ 31563adc6fbSStephen Hemminger __u8 tos; /* six MSB of (former) IPv4 TOS 31663adc6fbSStephen Hemminger are for dscp codepoint */ 31763adc6fbSStephen Hemminger __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 31863adc6fbSStephen Hemminger (see RFC 3260, sec. 4) */ 3191ca7768cSFrancesco Fondelli 320ca6549afSSteven Whitehouse /* MPLS */ 321ca6549afSSteven Whitehouse unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ 322ca6549afSSteven Whitehouse __be32 labels[MAX_MPLS_LABELS]; 323ca6549afSSteven Whitehouse 32434954ddcSFrancesco Fondelli /* VLAN/SVLAN (802.1Q/Q-in-Q) */ 32534954ddcSFrancesco Fondelli __u8 vlan_p; 32634954ddcSFrancesco Fondelli __u8 vlan_cfi; 32734954ddcSFrancesco Fondelli __u16 vlan_id; /* 0xffff means no vlan tag */ 32834954ddcSFrancesco Fondelli 32934954ddcSFrancesco Fondelli __u8 svlan_p; 33034954ddcSFrancesco Fondelli __u8 svlan_cfi; 33134954ddcSFrancesco Fondelli __u16 svlan_id; /* 0xffff means no svlan tag */ 33234954ddcSFrancesco Fondelli 3331da177e4SLinus Torvalds __u32 src_mac_count; /* How many MACs to iterate through */ 3341da177e4SLinus Torvalds __u32 dst_mac_count; /* How many MACs to iterate through */ 3351da177e4SLinus Torvalds 336f404e9a6SKris Katterjohn unsigned char dst_mac[ETH_ALEN]; 337f404e9a6SKris Katterjohn unsigned char src_mac[ETH_ALEN]; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds __u32 cur_dst_mac_offset; 3401da177e4SLinus Torvalds __u32 cur_src_mac_offset; 341252e3346SAl Viro __be32 cur_saddr; 342252e3346SAl Viro __be32 cur_daddr; 34366ed1e5eSEric Dumazet __u16 ip_id; 3441da177e4SLinus Torvalds __u16 cur_udp_dst; 3451da177e4SLinus Torvalds __u16 cur_udp_src; 34645b270f8SRobert Olsson __u16 cur_queue_map; 3471da177e4SLinus Torvalds __u32 cur_pkt_size; 348baac8564SEric Dumazet __u32 last_pkt_size; 3491da177e4SLinus Torvalds 3501da177e4SLinus Torvalds __u8 hh[14]; 3511da177e4SLinus Torvalds /* = { 3521da177e4SLinus Torvalds 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds We fill in SRC address later 3551da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3561da177e4SLinus Torvalds 0x08, 0x00 3571da177e4SLinus Torvalds }; 3581da177e4SLinus Torvalds */ 3591da177e4SLinus Torvalds __u16 pad; /* pad out the hh struct to an even 16 bytes */ 3601da177e4SLinus Torvalds 36163adc6fbSStephen Hemminger struct sk_buff *skb; /* skb we are to transmit next, used for when we 3621da177e4SLinus Torvalds * are transmitting the same one multiple times 3631da177e4SLinus Torvalds */ 36463adc6fbSStephen Hemminger struct net_device *odev; /* The out-going device. 36563adc6fbSStephen Hemminger * Note that the device should have it's 36663adc6fbSStephen Hemminger * pg_info pointer pointing back to this 36763adc6fbSStephen Hemminger * device. 36863adc6fbSStephen Hemminger * Set when the user specifies the out-going 36963adc6fbSStephen Hemminger * device name (not when the inject is 3701da177e4SLinus Torvalds * started as it used to do.) 3711da177e4SLinus Torvalds */ 372593f63b0SEric Dumazet char odevname[32]; 3731da177e4SLinus Torvalds struct flow_state *flows; 3741da177e4SLinus Torvalds unsigned cflows; /* Concurrent flows (config) */ 3751da177e4SLinus Torvalds unsigned lflow; /* Flow length (config) */ 3761da177e4SLinus Torvalds unsigned nflows; /* accumulated flows (stats) */ 377007a531bSJamal Hadi Salim unsigned curfl; /* current sequenced flow (state)*/ 37845b270f8SRobert Olsson 37945b270f8SRobert Olsson u16 queue_map_min; 38045b270f8SRobert Olsson u16 queue_map_max; 381e99b99b4SRobert Olsson int node; /* Memory node */ 38245b270f8SRobert Olsson 383a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 384a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 385a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 386a553e4a6SJamal Hadi Salim #endif 38739df232fSStephen Hemminger char result[512]; 3881da177e4SLinus Torvalds }; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds struct pktgen_hdr { 391252e3346SAl Viro __be32 pgh_magic; 392252e3346SAl Viro __be32 seq_num; 393252e3346SAl Viro __be32 tv_sec; 394252e3346SAl Viro __be32 tv_usec; 3951da177e4SLinus Torvalds }; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds struct pktgen_thread { 39863adc6fbSStephen Hemminger spinlock_t if_lock; /* for list of devices */ 399c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 400cdcdbe0bSLuiz Capitulino struct list_head th_list; 401ee74baa7SDavid S. Miller struct task_struct *tsk; 4021da177e4SLinus Torvalds char result[512]; 4031da177e4SLinus Torvalds 40463adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 40563adc6fbSStephen Hemminger stop ifs etc. */ 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds u32 control; 4081da177e4SLinus Torvalds int cpu; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds wait_queue_head_t queue; 411d3ede327SDenis V. Lunev struct completion start_done; 4121da177e4SLinus Torvalds }; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds #define REMOVE 1 4151da177e4SLinus Torvalds #define FIND 0 4161da177e4SLinus Torvalds 417fd29cf72SStephen Hemminger static inline ktime_t ktime_now(void) 4181da177e4SLinus Torvalds { 419fd29cf72SStephen Hemminger struct timespec ts; 420fd29cf72SStephen Hemminger ktime_get_ts(&ts); 421fd29cf72SStephen Hemminger 422fd29cf72SStephen Hemminger return timespec_to_ktime(ts); 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 425fd29cf72SStephen Hemminger /* This works even if 32 bit because of careful byte order choice */ 426fd29cf72SStephen Hemminger static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2) 4271da177e4SLinus Torvalds { 428fd29cf72SStephen Hemminger return cmp1.tv64 < cmp2.tv64; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 431c3d2f52dSStephen Hemminger static const char version[] = 432f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 433f9467eaeSJoe Perches "Version: " VERSION "\n"; 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4361da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 437222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4383e984840SEric Dumazet const char *ifname, bool exact); 4391da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4401da177e4SLinus Torvalds static void pktgen_run_all_threads(void); 441eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void); 4421da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void); 4433bda06a3SStephen Hemminger 4441da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4451da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 44639df232fSStephen Hemminger 4471da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]); 4481da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s, const char ip[16]); 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds /* Module parameters, defaults. */ 45165c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 45265c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 45365c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 45465c5b786SStephen Hemminger static int debug __read_mostly; 4551da177e4SLinus Torvalds 456222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 457cdcdbe0bSLuiz Capitulino static LIST_HEAD(pktgen_threads); 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4601da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4611da177e4SLinus Torvalds }; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds /* 4641da177e4SLinus Torvalds * /proc handling functions 4651da177e4SLinus Torvalds * 4661da177e4SLinus Torvalds */ 4671da177e4SLinus Torvalds 468d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 469d50a6b56SStephen Hemminger { 470c3d2f52dSStephen Hemminger seq_puts(seq, version); 471d50a6b56SStephen Hemminger return 0; 472d50a6b56SStephen Hemminger } 4731da177e4SLinus Torvalds 474d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4751da177e4SLinus Torvalds size_t count, loff_t *ppos) 4761da177e4SLinus Torvalds { 4771da177e4SLinus Torvalds int err = 0; 478d50a6b56SStephen Hemminger char data[128]; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) { 4811da177e4SLinus Torvalds err = -EPERM; 4821da177e4SLinus Torvalds goto out; 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 485d50a6b56SStephen Hemminger if (count > sizeof(data)) 486d50a6b56SStephen Hemminger count = sizeof(data); 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds if (copy_from_user(data, buf, count)) { 4891da177e4SLinus Torvalds err = -EFAULT; 490d50a6b56SStephen Hemminger goto out; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds data[count - 1] = 0; /* Make string */ 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds if (!strcmp(data, "stop")) 4951da177e4SLinus Torvalds pktgen_stop_all_threads_ifs(); 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds else if (!strcmp(data, "start")) 4981da177e4SLinus Torvalds pktgen_run_all_threads(); 4991da177e4SLinus Torvalds 500eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 501eb37b41cSJesse Brandeburg pktgen_reset_all_threads(); 502eb37b41cSJesse Brandeburg 5031da177e4SLinus Torvalds else 504f9467eaeSJoe Perches pr_warning("Unknown command: %s\n", data); 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds err = count; 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds out: 5091da177e4SLinus Torvalds return err; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 512d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5131da177e4SLinus Torvalds { 514d50a6b56SStephen Hemminger return single_open(file, pgctrl_show, PDE(inode)->data); 515d50a6b56SStephen Hemminger } 516d50a6b56SStephen Hemminger 5179a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 518d50a6b56SStephen Hemminger .owner = THIS_MODULE, 519d50a6b56SStephen Hemminger .open = pgctrl_open, 520d50a6b56SStephen Hemminger .read = seq_read, 521d50a6b56SStephen Hemminger .llseek = seq_lseek, 522d50a6b56SStephen Hemminger .write = pgctrl_write, 523d50a6b56SStephen Hemminger .release = single_release, 524d50a6b56SStephen Hemminger }; 525d50a6b56SStephen Hemminger 526d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 527d50a6b56SStephen Hemminger { 528648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 529fd29cf72SStephen Hemminger ktime_t stopped; 530fd29cf72SStephen Hemminger u64 idle; 5311da177e4SLinus Torvalds 532222f1806SLuiz Capitulino seq_printf(seq, 533222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 534222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 535222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5361da177e4SLinus Torvalds 537222f1806SLuiz Capitulino seq_printf(seq, 538fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 539fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 540593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5411da177e4SLinus Torvalds 542222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 543222f1806SLuiz Capitulino pkt_dev->lflow); 5441da177e4SLinus Torvalds 54545b270f8SRobert Olsson seq_printf(seq, 54645b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 54745b270f8SRobert Olsson pkt_dev->queue_map_min, 54845b270f8SRobert Olsson pkt_dev->queue_map_max); 54945b270f8SRobert Olsson 5501da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 5511da177e4SLinus Torvalds char b1[128], b2[128], b3[128]; 5521da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); 5531da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); 5541da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); 555222f1806SLuiz Capitulino seq_printf(seq, 556222f1806SLuiz Capitulino " saddr: %s min_saddr: %s max_saddr: %s\n", b1, 557222f1806SLuiz Capitulino b2, b3); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); 5601da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); 5611da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); 562222f1806SLuiz Capitulino seq_printf(seq, 563222f1806SLuiz Capitulino " daddr: %s min_daddr: %s max_daddr: %s\n", b1, 564222f1806SLuiz Capitulino b2, b3); 5651da177e4SLinus Torvalds 56663adc6fbSStephen Hemminger } else { 567222f1806SLuiz Capitulino seq_printf(seq, 56863adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 56963adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 57063adc6fbSStephen Hemminger seq_printf(seq, 57163adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 57263adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 57363adc6fbSStephen Hemminger } 5741da177e4SLinus Torvalds 575d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5761da177e4SLinus Torvalds 577e174961cSJohannes Berg seq_printf(seq, "%pM ", 578e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 579e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5801da177e4SLinus Torvalds 581d50a6b56SStephen Hemminger seq_printf(seq, "dst_mac: "); 582e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5831da177e4SLinus Torvalds 584222f1806SLuiz Capitulino seq_printf(seq, 58563adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 58663adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 587222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 588222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 5891da177e4SLinus Torvalds 590222f1806SLuiz Capitulino seq_printf(seq, 591ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 5921da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 5931da177e4SLinus Torvalds 594ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 595ca6549afSSteven Whitehouse unsigned i; 596ca6549afSSteven Whitehouse seq_printf(seq, " mpls: "); 597ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 598ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 599ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 600ca6549afSSteven Whitehouse } 601ca6549afSSteven Whitehouse 60263adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 60334954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 60463adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 60563adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 60634954ddcSFrancesco Fondelli 60763adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 60834954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 60963adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 61063adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 61134954ddcSFrancesco Fondelli 61263adc6fbSStephen Hemminger if (pkt_dev->tos) 6131ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6141ca7768cSFrancesco Fondelli 61563adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6161ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6171ca7768cSFrancesco Fondelli 618e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 619e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 620e99b99b4SRobert Olsson 621ca6549afSSteven Whitehouse seq_printf(seq, " Flags: "); 622ca6549afSSteven Whitehouse 6231da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 624d50a6b56SStephen Hemminger seq_printf(seq, "IPV6 "); 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 627d50a6b56SStephen Hemminger seq_printf(seq, "IPSRC_RND "); 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 630d50a6b56SStephen Hemminger seq_printf(seq, "IPDST_RND "); 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 633d50a6b56SStephen Hemminger seq_printf(seq, "TXSIZE_RND "); 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 636d50a6b56SStephen Hemminger seq_printf(seq, "UDPSRC_RND "); 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 639d50a6b56SStephen Hemminger seq_printf(seq, "UDPDST_RND "); 6401da177e4SLinus Torvalds 641ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 642ca6549afSSteven Whitehouse seq_printf(seq, "MPLS_RND "); 643ca6549afSSteven Whitehouse 64445b270f8SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_RND) 64545b270f8SRobert Olsson seq_printf(seq, "QUEUE_MAP_RND "); 64645b270f8SRobert Olsson 647e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 648e6fce5b9SRobert Olsson seq_printf(seq, "QUEUE_MAP_CPU "); 649e6fce5b9SRobert Olsson 650007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 651007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 652007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/ 653007a531bSJamal Hadi Salim else 654007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_RND "); 655007a531bSJamal Hadi Salim } 656007a531bSJamal Hadi Salim 657a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 658a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 659a553e4a6SJamal Hadi Salim seq_printf(seq, "IPSEC "); 660a553e4a6SJamal Hadi Salim #endif 661a553e4a6SJamal Hadi Salim 6621da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 663d50a6b56SStephen Hemminger seq_printf(seq, "MACSRC_RND "); 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 666d50a6b56SStephen Hemminger seq_printf(seq, "MACDST_RND "); 6671da177e4SLinus Torvalds 66834954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 66934954ddcSFrancesco Fondelli seq_printf(seq, "VID_RND "); 67034954ddcSFrancesco Fondelli 67134954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 67234954ddcSFrancesco Fondelli seq_printf(seq, "SVID_RND "); 67334954ddcSFrancesco Fondelli 674e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) 675e99b99b4SRobert Olsson seq_printf(seq, "NODE_ALLOC "); 676e99b99b4SRobert Olsson 677d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6781da177e4SLinus Torvalds 679fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 680fd29cf72SStephen Hemminger stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at; 681fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 682fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6831da177e4SLinus Torvalds 684222f1806SLuiz Capitulino seq_printf(seq, 685fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6861da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 687fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 688fd29cf72SStephen Hemminger 689fd29cf72SStephen Hemminger seq_printf(seq, 690fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 691fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 692fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 693fd29cf72SStephen Hemminger (unsigned long long) idle); 6941da177e4SLinus Torvalds 695222f1806SLuiz Capitulino seq_printf(seq, 696222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 697d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 698d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 7011da177e4SLinus Torvalds char b1[128], b2[128]; 7021da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); 7031da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); 704d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); 705222f1806SLuiz Capitulino } else 706d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", 7071da177e4SLinus Torvalds pkt_dev->cur_saddr, pkt_dev->cur_daddr); 7081da177e4SLinus Torvalds 709d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7101da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7111da177e4SLinus Torvalds 71245b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 71345b270f8SRobert Olsson 714d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds if (pkt_dev->result[0]) 717d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7181da177e4SLinus Torvalds else 719d50a6b56SStephen Hemminger seq_printf(seq, "Result: Idle\n"); 7201da177e4SLinus Torvalds 721d50a6b56SStephen Hemminger return 0; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 724ca6549afSSteven Whitehouse 72563adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 72663adc6fbSStephen Hemminger __u32 *num) 727ca6549afSSteven Whitehouse { 728ca6549afSSteven Whitehouse int i = 0; 729ca6549afSSteven Whitehouse *num = 0; 730ca6549afSSteven Whitehouse 7311ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 732*82fd5b5dSAndy Shevchenko int value; 733ca6549afSSteven Whitehouse char c; 734ca6549afSSteven Whitehouse *num <<= 4; 735ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 736ca6549afSSteven Whitehouse return -EFAULT; 737*82fd5b5dSAndy Shevchenko value = hex_to_bin(c); 738*82fd5b5dSAndy Shevchenko if (value >= 0) 739*82fd5b5dSAndy Shevchenko *num |= value; 740ca6549afSSteven Whitehouse else 741ca6549afSSteven Whitehouse break; 742ca6549afSSteven Whitehouse } 743ca6549afSSteven Whitehouse return i; 744ca6549afSSteven Whitehouse } 745ca6549afSSteven Whitehouse 746222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 747222f1806SLuiz Capitulino unsigned int maxlen) 7481da177e4SLinus Torvalds { 7491da177e4SLinus Torvalds int i; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7521da177e4SLinus Torvalds char c; 7531da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7541da177e4SLinus Torvalds return -EFAULT; 7551da177e4SLinus Torvalds switch (c) { 7561da177e4SLinus Torvalds case '\"': 7571da177e4SLinus Torvalds case '\n': 7581da177e4SLinus Torvalds case '\r': 7591da177e4SLinus Torvalds case '\t': 7601da177e4SLinus Torvalds case ' ': 7611da177e4SLinus Torvalds case '=': 7621da177e4SLinus Torvalds break; 7631da177e4SLinus Torvalds default: 7641da177e4SLinus Torvalds goto done; 7653ff50b79SStephen Hemminger } 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds done: 7681da177e4SLinus Torvalds return i; 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 771222f1806SLuiz Capitulino static unsigned long num_arg(const char __user * user_buffer, 772222f1806SLuiz Capitulino unsigned long maxlen, unsigned long *num) 7731da177e4SLinus Torvalds { 7741da177e4SLinus Torvalds int i = 0; 7751da177e4SLinus Torvalds *num = 0; 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds for (; i < maxlen; i++) { 7781da177e4SLinus Torvalds char c; 7791da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7801da177e4SLinus Torvalds return -EFAULT; 7811da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 7821da177e4SLinus Torvalds *num *= 10; 7831da177e4SLinus Torvalds *num += c - '0'; 7841da177e4SLinus Torvalds } else 7851da177e4SLinus Torvalds break; 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds return i; 7881da177e4SLinus Torvalds } 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 7911da177e4SLinus Torvalds { 7921da177e4SLinus Torvalds int i = 0; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds for (; i < maxlen; i++) { 7951da177e4SLinus Torvalds char c; 7961da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7971da177e4SLinus Torvalds return -EFAULT; 7981da177e4SLinus Torvalds switch (c) { 7991da177e4SLinus Torvalds case '\"': 8001da177e4SLinus Torvalds case '\n': 8011da177e4SLinus Torvalds case '\r': 8021da177e4SLinus Torvalds case '\t': 8031da177e4SLinus Torvalds case ' ': 8041da177e4SLinus Torvalds goto done_str; 8051da177e4SLinus Torvalds break; 8061da177e4SLinus Torvalds default: 8071da177e4SLinus Torvalds break; 8083ff50b79SStephen Hemminger } 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds done_str: 8111da177e4SLinus Torvalds return i; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 814ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 815ca6549afSSteven Whitehouse { 816ca6549afSSteven Whitehouse unsigned n = 0; 817ca6549afSSteven Whitehouse char c; 818ca6549afSSteven Whitehouse ssize_t i = 0; 819ca6549afSSteven Whitehouse int len; 820ca6549afSSteven Whitehouse 821ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 822ca6549afSSteven Whitehouse do { 823ca6549afSSteven Whitehouse __u32 tmp; 8241ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 825ca6549afSSteven Whitehouse if (len <= 0) 826ca6549afSSteven Whitehouse return len; 827ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 828ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 829ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 830ca6549afSSteven Whitehouse i += len; 831ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 832ca6549afSSteven Whitehouse return -EFAULT; 833ca6549afSSteven Whitehouse i++; 834ca6549afSSteven Whitehouse n++; 835ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 836ca6549afSSteven Whitehouse return -E2BIG; 837ca6549afSSteven Whitehouse } while (c == ','); 838ca6549afSSteven Whitehouse 839ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 840ca6549afSSteven Whitehouse return i; 841ca6549afSSteven Whitehouse } 842ca6549afSSteven Whitehouse 843222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 844222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 845222f1806SLuiz Capitulino loff_t * offset) 8461da177e4SLinus Torvalds { 8478a994a71SJoe Perches struct seq_file *seq = file->private_data; 848d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 8491da177e4SLinus Torvalds int i = 0, max, len; 8501da177e4SLinus Torvalds char name[16], valstr[32]; 8511da177e4SLinus Torvalds unsigned long value = 0; 8521da177e4SLinus Torvalds char *pg_result = NULL; 8531da177e4SLinus Torvalds int tmp = 0; 8541da177e4SLinus Torvalds char buf[128]; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds if (count < 1) { 859f9467eaeSJoe Perches pr_warning("wrong command format\n"); 8601da177e4SLinus Torvalds return -EINVAL; 8611da177e4SLinus Torvalds } 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds max = count - i; 8641da177e4SLinus Torvalds tmp = count_trail_chars(&user_buffer[i], max); 8651da177e4SLinus Torvalds if (tmp < 0) { 866f9467eaeSJoe Perches pr_warning("illegal format\n"); 8671da177e4SLinus Torvalds return tmp; 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds i += tmp; 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds /* Read variable name */ 8721da177e4SLinus Torvalds 8731da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 87463adc6fbSStephen Hemminger if (len < 0) 875222f1806SLuiz Capitulino return len; 87663adc6fbSStephen Hemminger 8771da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 8781da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 8791da177e4SLinus Torvalds return -EFAULT; 8801da177e4SLinus Torvalds i += len; 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds max = count - i; 8831da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 8841da177e4SLinus Torvalds if (len < 0) 8851da177e4SLinus Torvalds return len; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds i += len; 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds if (debug) { 8901da177e4SLinus Torvalds char tb[count + 1]; 8911da177e4SLinus Torvalds if (copy_from_user(tb, user_buffer, count)) 8921da177e4SLinus Torvalds return -EFAULT; 8931da177e4SLinus Torvalds tb[count] = 0; 89425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, 895d50a6b56SStephen Hemminger (unsigned long)count, tb); 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 8991da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 90063adc6fbSStephen Hemminger if (len < 0) 901222f1806SLuiz Capitulino return len; 90263adc6fbSStephen Hemminger 9031da177e4SLinus Torvalds i += len; 9041da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9051da177e4SLinus Torvalds value = 14 + 20 + 8; 9061da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9071da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9081da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9091da177e4SLinus Torvalds } 910222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 911222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9121da177e4SLinus Torvalds return count; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9161da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 91763adc6fbSStephen Hemminger if (len < 0) 918222f1806SLuiz Capitulino return len; 91963adc6fbSStephen Hemminger 9201da177e4SLinus Torvalds i += len; 9211da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9221da177e4SLinus Torvalds value = 14 + 20 + 8; 9231da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9241da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9251da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9261da177e4SLinus Torvalds } 927222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 928222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9291da177e4SLinus Torvalds return count; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds /* Shortcut for min = max */ 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9351da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 93663adc6fbSStephen Hemminger if (len < 0) 937222f1806SLuiz Capitulino return len; 93863adc6fbSStephen Hemminger 9391da177e4SLinus Torvalds i += len; 9401da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9411da177e4SLinus Torvalds value = 14 + 20 + 8; 9421da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9431da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9441da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9451da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9461da177e4SLinus Torvalds } 9471da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9481da177e4SLinus Torvalds return count; 9491da177e4SLinus Torvalds } 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9521da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 95363adc6fbSStephen Hemminger if (len < 0) 954222f1806SLuiz Capitulino return len; 95563adc6fbSStephen Hemminger 9561da177e4SLinus Torvalds i += len; 9571da177e4SLinus Torvalds debug = value; 9581da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9591da177e4SLinus Torvalds return count; 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9631da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 96463adc6fbSStephen Hemminger if (len < 0) 965222f1806SLuiz Capitulino return len; 96663adc6fbSStephen Hemminger 9671da177e4SLinus Torvalds i += len; 9681da177e4SLinus Torvalds pkt_dev->nfrags = value; 9691da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 9701da177e4SLinus Torvalds return count; 9711da177e4SLinus Torvalds } 9721da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9731da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97463adc6fbSStephen Hemminger if (len < 0) 975222f1806SLuiz Capitulino return len; 97663adc6fbSStephen Hemminger 9771da177e4SLinus Torvalds i += len; 978fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 979fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 980fd29cf72SStephen Hemminger else 9819240d715SEric Dumazet pkt_dev->delay = (u64)value; 982fd29cf72SStephen Hemminger 983fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 984fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9851da177e4SLinus Torvalds return count; 9861da177e4SLinus Torvalds } 98743d28b65SDaniel Turull if (!strcmp(name, "rate")) { 98843d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 98943d28b65SDaniel Turull if (len < 0) 99043d28b65SDaniel Turull return len; 99143d28b65SDaniel Turull 99243d28b65SDaniel Turull i += len; 99343d28b65SDaniel Turull if (!value) 99443d28b65SDaniel Turull return len; 99543d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 99643d28b65SDaniel Turull if (debug) 997f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 99843d28b65SDaniel Turull 99943d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 100043d28b65SDaniel Turull return count; 100143d28b65SDaniel Turull } 100243d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 100343d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 100443d28b65SDaniel Turull if (len < 0) 100543d28b65SDaniel Turull return len; 100643d28b65SDaniel Turull 100743d28b65SDaniel Turull i += len; 100843d28b65SDaniel Turull if (!value) 100943d28b65SDaniel Turull return len; 101043d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 101143d28b65SDaniel Turull if (debug) 1012f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 101343d28b65SDaniel Turull 101443d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 101543d28b65SDaniel Turull return count; 101643d28b65SDaniel Turull } 10171da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10181da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 101963adc6fbSStephen Hemminger if (len < 0) 1020222f1806SLuiz Capitulino return len; 102163adc6fbSStephen Hemminger 10221da177e4SLinus Torvalds i += len; 10231da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10241da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10251da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10261da177e4SLinus Torvalds } 10271da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10281da177e4SLinus Torvalds return count; 10291da177e4SLinus Torvalds } 10301da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10311da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 103263adc6fbSStephen Hemminger if (len < 0) 1033222f1806SLuiz Capitulino return len; 103463adc6fbSStephen Hemminger 10351da177e4SLinus Torvalds i += len; 10361da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10371da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10381da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10391da177e4SLinus Torvalds } 10401da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10411da177e4SLinus Torvalds return count; 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10441da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104563adc6fbSStephen Hemminger if (len < 0) 1046222f1806SLuiz Capitulino return len; 104763adc6fbSStephen Hemminger 10481da177e4SLinus Torvalds i += len; 10491da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10501da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10511da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10541da177e4SLinus Torvalds return count; 10551da177e4SLinus Torvalds } 10561da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10571da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105863adc6fbSStephen Hemminger if (len < 0) 1059222f1806SLuiz Capitulino return len; 106063adc6fbSStephen Hemminger 10611da177e4SLinus Torvalds i += len; 10621da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10631da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10641da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10671da177e4SLinus Torvalds return count; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10701da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107163adc6fbSStephen Hemminger if (len < 0) 1072222f1806SLuiz Capitulino return len; 107363adc6fbSStephen Hemminger 10741da177e4SLinus Torvalds i += len; 10751da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10781da177e4SLinus Torvalds return count; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10811da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108263adc6fbSStephen Hemminger if (len < 0) 1083222f1806SLuiz Capitulino return len; 108463adc6fbSStephen Hemminger 10851da177e4SLinus Torvalds i += len; 10861da177e4SLinus Torvalds pkt_dev->count = value; 10871da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 10881da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 10891da177e4SLinus Torvalds return count; 10901da177e4SLinus Torvalds } 10911da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 10921da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109363adc6fbSStephen Hemminger if (len < 0) 1094222f1806SLuiz Capitulino return len; 109563adc6fbSStephen Hemminger 10961da177e4SLinus Torvalds i += len; 10971da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 10981da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 10991da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11001da177e4SLinus Torvalds } 1101222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1102222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11031da177e4SLinus Torvalds return count; 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11061da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110763adc6fbSStephen Hemminger if (len < 0) 1108222f1806SLuiz Capitulino return len; 110963adc6fbSStephen Hemminger 11101da177e4SLinus Torvalds i += len; 11111da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11121da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11131da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11141da177e4SLinus Torvalds } 1115222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1116222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11171da177e4SLinus Torvalds return count; 11181da177e4SLinus Torvalds } 1119e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1120e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1121e99b99b4SRobert Olsson if (len < 0) 1122e99b99b4SRobert Olsson return len; 1123e99b99b4SRobert Olsson 1124e99b99b4SRobert Olsson i += len; 1125e99b99b4SRobert Olsson 1126e99b99b4SRobert Olsson if (node_possible(value)) { 1127e99b99b4SRobert Olsson pkt_dev->node = value; 1128e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 1129e99b99b4SRobert Olsson } 1130e99b99b4SRobert Olsson else 1131e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1132e99b99b4SRobert Olsson return count; 1133e99b99b4SRobert Olsson } 11341da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11351da177e4SLinus Torvalds char f[32]; 11361da177e4SLinus Torvalds memset(f, 0, 32); 11371da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 113863adc6fbSStephen Hemminger if (len < 0) 1139222f1806SLuiz Capitulino return len; 114063adc6fbSStephen Hemminger 11411da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11421da177e4SLinus Torvalds return -EFAULT; 11431da177e4SLinus Torvalds i += len; 11441da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11451da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11481da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11511da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11521da177e4SLinus Torvalds 11531da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11541da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11571da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11601da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11631da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11661da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11691da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11721da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11751da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11781da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11811da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11841da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11851da177e4SLinus Torvalds 1186ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1187ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1188ca6549afSSteven Whitehouse 1189ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1190ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1191ca6549afSSteven Whitehouse 119234954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 119334954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 119434954ddcSFrancesco Fondelli 119534954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 119634954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 119734954ddcSFrancesco Fondelli 119834954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 119934954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 120034954ddcSFrancesco Fondelli 120134954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 120234954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 120334954ddcSFrancesco Fondelli 1204007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1205007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1206007a531bSJamal Hadi Salim 120745b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 120845b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 120945b270f8SRobert Olsson 121045b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 121145b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1212e6fce5b9SRobert Olsson 1213e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1214e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1215e6fce5b9SRobert Olsson 1216e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1217e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1218a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1219a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1220a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1221a553e4a6SJamal Hadi Salim #endif 1222a553e4a6SJamal Hadi Salim 12231ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12241ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12251ca7768cSFrancesco Fondelli 1226e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1227e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1228e99b99b4SRobert Olsson 1229e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1230e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1231e99b99b4SRobert Olsson 12321da177e4SLinus Torvalds else { 1233222f1806SLuiz Capitulino sprintf(pg_result, 1234222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12351da177e4SLinus Torvalds f, 12361ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 1237e99b99b4SRobert Olsson "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n"); 12381da177e4SLinus Torvalds return count; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12411da177e4SLinus Torvalds return count; 12421da177e4SLinus Torvalds } 12431da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12441da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 124563adc6fbSStephen Hemminger if (len < 0) 1246222f1806SLuiz Capitulino return len; 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12491da177e4SLinus Torvalds return -EFAULT; 12501da177e4SLinus Torvalds buf[len] = 0; 12511da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12521da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12531da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12541da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12551da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds if (debug) 125825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_min set to: %s\n", 1259222f1806SLuiz Capitulino pkt_dev->dst_min); 12601da177e4SLinus Torvalds i += len; 12611da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12621da177e4SLinus Torvalds return count; 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12651da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 126663adc6fbSStephen Hemminger if (len < 0) 1267222f1806SLuiz Capitulino return len; 126863adc6fbSStephen Hemminger 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12711da177e4SLinus Torvalds return -EFAULT; 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds buf[len] = 0; 12741da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12751da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12761da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 12771da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12781da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12791da177e4SLinus Torvalds } 12801da177e4SLinus Torvalds if (debug) 128125a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_max set to: %s\n", 1282222f1806SLuiz Capitulino pkt_dev->dst_max); 12831da177e4SLinus Torvalds i += len; 12841da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12851da177e4SLinus Torvalds return count; 12861da177e4SLinus Torvalds } 12871da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12881da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1289222f1806SLuiz Capitulino if (len < 0) 1290222f1806SLuiz Capitulino return len; 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12951da177e4SLinus Torvalds return -EFAULT; 12961da177e4SLinus Torvalds buf[len] = 0; 12971da177e4SLinus Torvalds 12981da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 12991da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 13021da177e4SLinus Torvalds 13031da177e4SLinus Torvalds if (debug) 130425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf); 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds i += len; 13071da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13081da177e4SLinus Torvalds return count; 13091da177e4SLinus Torvalds } 13101da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13111da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1312222f1806SLuiz Capitulino if (len < 0) 1313222f1806SLuiz Capitulino return len; 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13181da177e4SLinus Torvalds return -EFAULT; 13191da177e4SLinus Torvalds buf[len] = 0; 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13221da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13231da177e4SLinus Torvalds 1324222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev->cur_in6_daddr, 1325222f1806SLuiz Capitulino &pkt_dev->min_in6_daddr); 13261da177e4SLinus Torvalds if (debug) 132725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf); 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds i += len; 13301da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13311da177e4SLinus Torvalds return count; 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13341da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1335222f1806SLuiz Capitulino if (len < 0) 1336222f1806SLuiz Capitulino return len; 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13411da177e4SLinus Torvalds return -EFAULT; 13421da177e4SLinus Torvalds buf[len] = 0; 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13451da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13461da177e4SLinus Torvalds 13471da177e4SLinus Torvalds if (debug) 134825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds i += len; 13511da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13521da177e4SLinus Torvalds return count; 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13551da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1356222f1806SLuiz Capitulino if (len < 0) 1357222f1806SLuiz Capitulino return len; 13581da177e4SLinus Torvalds 13591da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13621da177e4SLinus Torvalds return -EFAULT; 13631da177e4SLinus Torvalds buf[len] = 0; 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13661da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 13691da177e4SLinus Torvalds 13701da177e4SLinus Torvalds if (debug) 137125a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf); 13721da177e4SLinus Torvalds 13731da177e4SLinus Torvalds i += len; 13741da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13751da177e4SLinus Torvalds return count; 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13781da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 137963adc6fbSStephen Hemminger if (len < 0) 1380222f1806SLuiz Capitulino return len; 138163adc6fbSStephen Hemminger 13821da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13831da177e4SLinus Torvalds return -EFAULT; 13841da177e4SLinus Torvalds buf[len] = 0; 13851da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13861da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13871da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 13881da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13891da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13901da177e4SLinus Torvalds } 13911da177e4SLinus Torvalds if (debug) 139225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_min set to: %s\n", 1393222f1806SLuiz Capitulino pkt_dev->src_min); 13941da177e4SLinus Torvalds i += len; 13951da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 13961da177e4SLinus Torvalds return count; 13971da177e4SLinus Torvalds } 13981da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 13991da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 140063adc6fbSStephen Hemminger if (len < 0) 1401222f1806SLuiz Capitulino return len; 140263adc6fbSStephen Hemminger 14031da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14041da177e4SLinus Torvalds return -EFAULT; 14051da177e4SLinus Torvalds buf[len] = 0; 14061da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14071da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14081da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14091da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14101da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds if (debug) 141325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_max set to: %s\n", 1414222f1806SLuiz Capitulino pkt_dev->src_max); 14151da177e4SLinus Torvalds i += len; 14161da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14171da177e4SLinus Torvalds return count; 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14201da177e4SLinus Torvalds char *v = valstr; 1421f404e9a6SKris Katterjohn unsigned char old_dmac[ETH_ALEN]; 14221da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1423f404e9a6SKris Katterjohn memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); 14241da177e4SLinus Torvalds 14251da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 142663adc6fbSStephen Hemminger if (len < 0) 1427222f1806SLuiz Capitulino return len; 142863adc6fbSStephen Hemminger 14291da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14301da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14311da177e4SLinus Torvalds return -EFAULT; 14321da177e4SLinus Torvalds i += len; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { 1435451e07a2SAndy Shevchenko int value; 1436451e07a2SAndy Shevchenko 1437451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1438451e07a2SAndy Shevchenko if (value >= 0) 1439451e07a2SAndy Shevchenko *m = *m * 16 + value; 1440451e07a2SAndy Shevchenko 14411da177e4SLinus Torvalds if (*v == ':') { 14421da177e4SLinus Torvalds m++; 14431da177e4SLinus Torvalds *m = 0; 14441da177e4SLinus Torvalds } 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds /* Set up Dest MAC */ 1448f404e9a6SKris Katterjohn if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) 1449f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 14521da177e4SLinus Torvalds return count; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14551da177e4SLinus Torvalds char *v = valstr; 1456ce5d0b47SAdit Ranadive unsigned char old_smac[ETH_ALEN]; 14571da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 14581da177e4SLinus Torvalds 1459ce5d0b47SAdit Ranadive memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); 1460ce5d0b47SAdit Ranadive 14611da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 146263adc6fbSStephen Hemminger if (len < 0) 1463222f1806SLuiz Capitulino return len; 146463adc6fbSStephen Hemminger 14651da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14661da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14671da177e4SLinus Torvalds return -EFAULT; 14681da177e4SLinus Torvalds i += len; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { 1471451e07a2SAndy Shevchenko int value; 1472451e07a2SAndy Shevchenko 1473451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1474451e07a2SAndy Shevchenko if (value >= 0) 1475451e07a2SAndy Shevchenko *m = *m * 16 + value; 1476451e07a2SAndy Shevchenko 14771da177e4SLinus Torvalds if (*v == ':') { 14781da177e4SLinus Torvalds m++; 14791da177e4SLinus Torvalds *m = 0; 14801da177e4SLinus Torvalds } 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds 1483ce5d0b47SAdit Ranadive /* Set up Src MAC */ 1484ce5d0b47SAdit Ranadive if (compare_ether_addr(old_smac, pkt_dev->src_mac)) 1485ce5d0b47SAdit Ranadive memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); 1486ce5d0b47SAdit Ranadive 14871da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 14881da177e4SLinus Torvalds return count; 14891da177e4SLinus Torvalds } 14901da177e4SLinus Torvalds 14911da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14921da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 14931da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 14941da177e4SLinus Torvalds return count; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 14981da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 149963adc6fbSStephen Hemminger if (len < 0) 1500222f1806SLuiz Capitulino return len; 150163adc6fbSStephen Hemminger 15021da177e4SLinus Torvalds i += len; 15031da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15041da177e4SLinus Torvalds value = MAX_CFLOWS; 15051da177e4SLinus Torvalds 15061da177e4SLinus Torvalds pkt_dev->cflows = value; 15071da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15081da177e4SLinus Torvalds return count; 15091da177e4SLinus Torvalds } 15101da177e4SLinus Torvalds 15111da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15121da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 151363adc6fbSStephen Hemminger if (len < 0) 1514222f1806SLuiz Capitulino return len; 151563adc6fbSStephen Hemminger 15161da177e4SLinus Torvalds i += len; 15171da177e4SLinus Torvalds pkt_dev->lflow = value; 15181da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15191da177e4SLinus Torvalds return count; 15201da177e4SLinus Torvalds } 15211da177e4SLinus Torvalds 152245b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 152345b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 152463adc6fbSStephen Hemminger if (len < 0) 152545b270f8SRobert Olsson return len; 152663adc6fbSStephen Hemminger 152745b270f8SRobert Olsson i += len; 152845b270f8SRobert Olsson pkt_dev->queue_map_min = value; 152945b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 153045b270f8SRobert Olsson return count; 153145b270f8SRobert Olsson } 153245b270f8SRobert Olsson 153345b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 153445b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 153563adc6fbSStephen Hemminger if (len < 0) 153645b270f8SRobert Olsson return len; 153763adc6fbSStephen Hemminger 153845b270f8SRobert Olsson i += len; 153945b270f8SRobert Olsson pkt_dev->queue_map_max = value; 154045b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 154145b270f8SRobert Olsson return count; 154245b270f8SRobert Olsson } 154345b270f8SRobert Olsson 1544ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 1545cfcabdccSStephen Hemminger unsigned n, cnt; 1546cfcabdccSStephen Hemminger 1547ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1548cfcabdccSStephen Hemminger if (len < 0) 1549cfcabdccSStephen Hemminger return len; 1550ca6549afSSteven Whitehouse i += len; 1551cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1552ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1553cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1554ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1555ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 155634954ddcSFrancesco Fondelli 155734954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 155834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 155934954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 156034954ddcSFrancesco Fondelli 156134954ddcSFrancesco Fondelli if (debug) 156225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); 156334954ddcSFrancesco Fondelli } 156434954ddcSFrancesco Fondelli return count; 156534954ddcSFrancesco Fondelli } 156634954ddcSFrancesco Fondelli 156734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 156834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 156963adc6fbSStephen Hemminger if (len < 0) 157034954ddcSFrancesco Fondelli return len; 157163adc6fbSStephen Hemminger 157234954ddcSFrancesco Fondelli i += len; 157334954ddcSFrancesco Fondelli if (value <= 4095) { 157434954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 157534954ddcSFrancesco Fondelli 157634954ddcSFrancesco Fondelli if (debug) 157725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN turned on\n"); 157834954ddcSFrancesco Fondelli 157934954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 158025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 158134954ddcSFrancesco Fondelli 158234954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 158334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 158434954ddcSFrancesco Fondelli } else { 158534954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 158634954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 158734954ddcSFrancesco Fondelli 158834954ddcSFrancesco Fondelli if (debug) 158925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 159034954ddcSFrancesco Fondelli } 159134954ddcSFrancesco Fondelli return count; 159234954ddcSFrancesco Fondelli } 159334954ddcSFrancesco Fondelli 159434954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 159534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 159663adc6fbSStephen Hemminger if (len < 0) 159734954ddcSFrancesco Fondelli return len; 159863adc6fbSStephen Hemminger 159934954ddcSFrancesco Fondelli i += len; 160034954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 160134954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 160234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 160334954ddcSFrancesco Fondelli } else { 160434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 160534954ddcSFrancesco Fondelli } 160634954ddcSFrancesco Fondelli return count; 160734954ddcSFrancesco Fondelli } 160834954ddcSFrancesco Fondelli 160934954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 161034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 161163adc6fbSStephen Hemminger if (len < 0) 161234954ddcSFrancesco Fondelli return len; 161363adc6fbSStephen Hemminger 161434954ddcSFrancesco Fondelli i += len; 161534954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 161634954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 161734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 161834954ddcSFrancesco Fondelli } else { 161934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 162034954ddcSFrancesco Fondelli } 162134954ddcSFrancesco Fondelli return count; 162234954ddcSFrancesco Fondelli } 162334954ddcSFrancesco Fondelli 162434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 162534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 162663adc6fbSStephen Hemminger if (len < 0) 162734954ddcSFrancesco Fondelli return len; 162863adc6fbSStephen Hemminger 162934954ddcSFrancesco Fondelli i += len; 163034954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 163134954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 163234954ddcSFrancesco Fondelli 163334954ddcSFrancesco Fondelli if (debug) 163425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); 163534954ddcSFrancesco Fondelli 163634954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 163725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 163834954ddcSFrancesco Fondelli 163934954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 164034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 164134954ddcSFrancesco Fondelli } else { 164234954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164334954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 164434954ddcSFrancesco Fondelli 164534954ddcSFrancesco Fondelli if (debug) 164625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 164734954ddcSFrancesco Fondelli } 164834954ddcSFrancesco Fondelli return count; 164934954ddcSFrancesco Fondelli } 165034954ddcSFrancesco Fondelli 165134954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 165234954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 165363adc6fbSStephen Hemminger if (len < 0) 165434954ddcSFrancesco Fondelli return len; 165563adc6fbSStephen Hemminger 165634954ddcSFrancesco Fondelli i += len; 165734954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 165834954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 165934954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 166034954ddcSFrancesco Fondelli } else { 166134954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 166234954ddcSFrancesco Fondelli } 166334954ddcSFrancesco Fondelli return count; 166434954ddcSFrancesco Fondelli } 166534954ddcSFrancesco Fondelli 166634954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 166734954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 166863adc6fbSStephen Hemminger if (len < 0) 166934954ddcSFrancesco Fondelli return len; 167063adc6fbSStephen Hemminger 167134954ddcSFrancesco Fondelli i += len; 167234954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 167334954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 167434954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 167534954ddcSFrancesco Fondelli } else { 167634954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 167734954ddcSFrancesco Fondelli } 1678ca6549afSSteven Whitehouse return count; 1679ca6549afSSteven Whitehouse } 1680ca6549afSSteven Whitehouse 16811ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16821ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16831ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 168463adc6fbSStephen Hemminger if (len < 0) 16851ca7768cSFrancesco Fondelli return len; 168663adc6fbSStephen Hemminger 16871ca7768cSFrancesco Fondelli i += len; 16881ca7768cSFrancesco Fondelli if (len == 2) { 16891ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16901ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16911ca7768cSFrancesco Fondelli } else { 16921ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16931ca7768cSFrancesco Fondelli } 16941ca7768cSFrancesco Fondelli return count; 16951ca7768cSFrancesco Fondelli } 16961ca7768cSFrancesco Fondelli 16971ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 16981ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16991ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 170063adc6fbSStephen Hemminger if (len < 0) 17011ca7768cSFrancesco Fondelli return len; 170263adc6fbSStephen Hemminger 17031ca7768cSFrancesco Fondelli i += len; 17041ca7768cSFrancesco Fondelli if (len == 2) { 17051ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17061ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17071ca7768cSFrancesco Fondelli } else { 17081ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17091ca7768cSFrancesco Fondelli } 17101ca7768cSFrancesco Fondelli return count; 17111ca7768cSFrancesco Fondelli } 17121ca7768cSFrancesco Fondelli 17131da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17141da177e4SLinus Torvalds return -EINVAL; 17151da177e4SLinus Torvalds } 17161da177e4SLinus Torvalds 1717d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17181da177e4SLinus Torvalds { 1719d50a6b56SStephen Hemminger return single_open(file, pktgen_if_show, PDE(inode)->data); 17201da177e4SLinus Torvalds } 17211da177e4SLinus Torvalds 17229a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1723d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1724d50a6b56SStephen Hemminger .open = pktgen_if_open, 1725d50a6b56SStephen Hemminger .read = seq_read, 1726d50a6b56SStephen Hemminger .llseek = seq_lseek, 1727d50a6b56SStephen Hemminger .write = pktgen_if_write, 1728d50a6b56SStephen Hemminger .release = single_release, 1729d50a6b56SStephen Hemminger }; 1730d50a6b56SStephen Hemminger 1731d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1732d50a6b56SStephen Hemminger { 1733d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1734648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1735d50a6b56SStephen Hemminger 1736d50a6b56SStephen Hemminger BUG_ON(!t); 1737d50a6b56SStephen Hemminger 1738d50a6b56SStephen Hemminger seq_printf(seq, "Running: "); 17391da177e4SLinus Torvalds 17401da177e4SLinus Torvalds if_lock(t); 1741c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17421da177e4SLinus Torvalds if (pkt_dev->running) 1743593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17441da177e4SLinus Torvalds 1745d50a6b56SStephen Hemminger seq_printf(seq, "\nStopped: "); 17461da177e4SLinus Torvalds 1747c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17481da177e4SLinus Torvalds if (!pkt_dev->running) 1749593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17501da177e4SLinus Torvalds 17511da177e4SLinus Torvalds if (t->result[0]) 1752d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17531da177e4SLinus Torvalds else 1754d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: NA\n"); 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds if_unlock(t); 17571da177e4SLinus Torvalds 1758d50a6b56SStephen Hemminger return 0; 17591da177e4SLinus Torvalds } 17601da177e4SLinus Torvalds 1761d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1762d50a6b56SStephen Hemminger const char __user * user_buffer, 1763d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17641da177e4SLinus Torvalds { 17658a994a71SJoe Perches struct seq_file *seq = file->private_data; 1766d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 17671da177e4SLinus Torvalds int i = 0, max, len, ret; 17681da177e4SLinus Torvalds char name[40]; 17691da177e4SLinus Torvalds char *pg_result; 17701da177e4SLinus Torvalds 17711da177e4SLinus Torvalds if (count < 1) { 17721da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17731da177e4SLinus Torvalds return -EINVAL; 17741da177e4SLinus Torvalds } 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds max = count - i; 17771da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17781da177e4SLinus Torvalds if (len < 0) 17791da177e4SLinus Torvalds return len; 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds i += len; 17821da177e4SLinus Torvalds 17831da177e4SLinus Torvalds /* Read variable name */ 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 17861da177e4SLinus Torvalds if (len < 0) 17871da177e4SLinus Torvalds return len; 17881da177e4SLinus Torvalds 17891da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 17901da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 17911da177e4SLinus Torvalds return -EFAULT; 17921da177e4SLinus Torvalds i += len; 17931da177e4SLinus Torvalds 17941da177e4SLinus Torvalds max = count - i; 17951da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17961da177e4SLinus Torvalds if (len < 0) 17971da177e4SLinus Torvalds return len; 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds i += len; 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds if (debug) 180225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", 180325a8b254SDavid S. Miller name, (unsigned long)count); 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds if (!t) { 1806f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 18071da177e4SLinus Torvalds ret = -EINVAL; 18081da177e4SLinus Torvalds goto out; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds pg_result = &(t->result[0]); 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18141da177e4SLinus Torvalds char f[32]; 18151da177e4SLinus Torvalds memset(f, 0, 32); 18161da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18171da177e4SLinus Torvalds if (len < 0) { 18181da177e4SLinus Torvalds ret = len; 18191da177e4SLinus Torvalds goto out; 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18221da177e4SLinus Torvalds return -EFAULT; 18231da177e4SLinus Torvalds i += len; 18246146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18251da177e4SLinus Torvalds pktgen_add_device(t, f); 18266146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18271da177e4SLinus Torvalds ret = count; 18281da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 18291da177e4SLinus Torvalds goto out; 18301da177e4SLinus Torvalds } 18311da177e4SLinus Torvalds 18321da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18336146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 183495ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18356146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1836121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18371da177e4SLinus Torvalds ret = count; 18381da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18391da177e4SLinus Torvalds goto out; 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds 18421da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1843b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18441da177e4SLinus Torvalds ret = count; 18451da177e4SLinus Torvalds goto out; 18461da177e4SLinus Torvalds } 18471da177e4SLinus Torvalds 18481da177e4SLinus Torvalds ret = -EINVAL; 18491da177e4SLinus Torvalds out: 18501da177e4SLinus Torvalds return ret; 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 1853d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18541da177e4SLinus Torvalds { 1855d50a6b56SStephen Hemminger return single_open(file, pktgen_thread_show, PDE(inode)->data); 18561da177e4SLinus Torvalds } 18571da177e4SLinus Torvalds 18589a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1859d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1860d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1861d50a6b56SStephen Hemminger .read = seq_read, 1862d50a6b56SStephen Hemminger .llseek = seq_lseek, 1863d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1864d50a6b56SStephen Hemminger .release = single_release, 1865d50a6b56SStephen Hemminger }; 18661da177e4SLinus Torvalds 18671da177e4SLinus Torvalds /* Think find or remove for NN */ 18681da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) 18691da177e4SLinus Torvalds { 18701da177e4SLinus Torvalds struct pktgen_thread *t; 18711da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18723e984840SEric Dumazet bool exact = (remove == FIND); 18731da177e4SLinus Torvalds 1874cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 18753e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18761da177e4SLinus Torvalds if (pkt_dev) { 18771da177e4SLinus Torvalds if (remove) { 18781da177e4SLinus Torvalds if_lock(t); 187995ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 188095ed63f7SArthur Kepner t->control |= T_REMDEV; 18811da177e4SLinus Torvalds if_unlock(t); 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds break; 18841da177e4SLinus Torvalds } 18851da177e4SLinus Torvalds } 18861da177e4SLinus Torvalds return pkt_dev; 18871da177e4SLinus Torvalds } 18881da177e4SLinus Torvalds 188995ed63f7SArthur Kepner /* 189095ed63f7SArthur Kepner * mark a device for removal 189195ed63f7SArthur Kepner */ 189239df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname) 18931da177e4SLinus Torvalds { 18941da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 189595ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 189695ed63f7SArthur Kepner int i = 0; 189795ed63f7SArthur Kepner 18986146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1899f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 190095ed63f7SArthur Kepner 190195ed63f7SArthur Kepner while (1) { 190295ed63f7SArthur Kepner 190395ed63f7SArthur Kepner pkt_dev = __pktgen_NN_threads(ifname, REMOVE); 1904222f1806SLuiz Capitulino if (pkt_dev == NULL) 1905222f1806SLuiz Capitulino break; /* success */ 190695ed63f7SArthur Kepner 19076146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1908f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1909f9467eaeSJoe Perches __func__, ifname); 191095ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19116146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 191295ed63f7SArthur Kepner 191395ed63f7SArthur Kepner if (++i >= max_tries) { 1914f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1915f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 191695ed63f7SArthur Kepner break; 191795ed63f7SArthur Kepner } 191895ed63f7SArthur Kepner 191995ed63f7SArthur Kepner } 192095ed63f7SArthur Kepner 19216146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 192239df232fSStephen Hemminger } 192395ed63f7SArthur Kepner 192439df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev) 192539df232fSStephen Hemminger { 192639df232fSStephen Hemminger struct pktgen_thread *t; 192739df232fSStephen Hemminger 192839df232fSStephen Hemminger list_for_each_entry(t, &pktgen_threads, th_list) { 192939df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 193039df232fSStephen Hemminger 193139df232fSStephen Hemminger list_for_each_entry(pkt_dev, &t->if_list, list) { 193239df232fSStephen Hemminger if (pkt_dev->odev != dev) 193339df232fSStephen Hemminger continue; 193439df232fSStephen Hemminger 193539df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 193639df232fSStephen Hemminger 19372975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19382975315bSAlexey Dobriyan pg_proc_dir, 19392975315bSAlexey Dobriyan &pktgen_if_fops, 19402975315bSAlexey Dobriyan pkt_dev); 194139df232fSStephen Hemminger if (!pkt_dev->entry) 1942f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1943f9467eaeSJoe Perches dev->name); 194439df232fSStephen Hemminger break; 194539df232fSStephen Hemminger } 194639df232fSStephen Hemminger } 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 1949222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1950222f1806SLuiz Capitulino unsigned long event, void *ptr) 19511da177e4SLinus Torvalds { 195239df232fSStephen Hemminger struct net_device *dev = ptr; 19531da177e4SLinus Torvalds 1954721499e8SYOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 1955e9dc8653SEric W. Biederman return NOTIFY_DONE; 1956e9dc8653SEric W. Biederman 19571da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19581da177e4SLinus Torvalds * as we run under the RTNL lock. 19591da177e4SLinus Torvalds */ 19601da177e4SLinus Torvalds 19611da177e4SLinus Torvalds switch (event) { 196239df232fSStephen Hemminger case NETDEV_CHANGENAME: 196339df232fSStephen Hemminger pktgen_change_name(dev); 19641da177e4SLinus Torvalds break; 19651da177e4SLinus Torvalds 19661da177e4SLinus Torvalds case NETDEV_UNREGISTER: 196795ed63f7SArthur Kepner pktgen_mark_device(dev->name); 19681da177e4SLinus Torvalds break; 19693ff50b79SStephen Hemminger } 19701da177e4SLinus Torvalds 19711da177e4SLinus Torvalds return NOTIFY_DONE; 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds 197463adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, 197563adc6fbSStephen Hemminger const char *ifname) 1976e6fce5b9SRobert Olsson { 1977e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1978e6fce5b9SRobert Olsson int i = 0; 1979e6fce5b9SRobert Olsson 1980e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 1981e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 1982e6fce5b9SRobert Olsson break; 1983e6fce5b9SRobert Olsson 1984e6fce5b9SRobert Olsson b[i] = ifname[i]; 1985e6fce5b9SRobert Olsson } 1986e6fce5b9SRobert Olsson b[i] = 0; 1987e6fce5b9SRobert Olsson 1988e6fce5b9SRobert Olsson return dev_get_by_name(&init_net, b); 1989e6fce5b9SRobert Olsson } 1990e6fce5b9SRobert Olsson 1991e6fce5b9SRobert Olsson 19921da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 19931da177e4SLinus Torvalds 199439df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) 1995222f1806SLuiz Capitulino { 19961da177e4SLinus Torvalds struct net_device *odev; 199739df232fSStephen Hemminger int err; 19981da177e4SLinus Torvalds 19991da177e4SLinus Torvalds /* Clean old setups */ 20001da177e4SLinus Torvalds if (pkt_dev->odev) { 20011da177e4SLinus Torvalds dev_put(pkt_dev->odev); 20021da177e4SLinus Torvalds pkt_dev->odev = NULL; 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds 2005e6fce5b9SRobert Olsson odev = pktgen_dev_get_by_name(pkt_dev, ifname); 20061da177e4SLinus Torvalds if (!odev) { 2007f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 200839df232fSStephen Hemminger return -ENODEV; 20091da177e4SLinus Torvalds } 201039df232fSStephen Hemminger 20111da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2012f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 201339df232fSStephen Hemminger err = -EINVAL; 201439df232fSStephen Hemminger } else if (!netif_running(odev)) { 2015f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 201639df232fSStephen Hemminger err = -ENETDOWN; 201739df232fSStephen Hemminger } else { 20181da177e4SLinus Torvalds pkt_dev->odev = odev; 201939df232fSStephen Hemminger return 0; 202039df232fSStephen Hemminger } 20211da177e4SLinus Torvalds 20221da177e4SLinus Torvalds dev_put(odev); 202339df232fSStephen Hemminger return err; 20241da177e4SLinus Torvalds } 20251da177e4SLinus Torvalds 20261da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20271da177e4SLinus Torvalds * structure to have the right information to create/send packets 20281da177e4SLinus Torvalds */ 20291da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20301da177e4SLinus Torvalds { 203164c00d81SAndrew Gallatin int ntxq; 203264c00d81SAndrew Gallatin 20331da177e4SLinus Torvalds if (!pkt_dev->odev) { 2034f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2035222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2036222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20371da177e4SLinus Torvalds return; 20381da177e4SLinus Torvalds } 20391da177e4SLinus Torvalds 204064c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 204164c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2042bfdbc0acSRobert Olsson 204364c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2044f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 204588271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2046593f63b0SEric Dumazet pkt_dev->odevname); 204764c00d81SAndrew Gallatin pkt_dev->queue_map_min = ntxq - 1; 204864c00d81SAndrew Gallatin } 204988271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2050f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 205188271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2052593f63b0SEric Dumazet pkt_dev->odevname); 205364c00d81SAndrew Gallatin pkt_dev->queue_map_max = ntxq - 1; 205464c00d81SAndrew Gallatin } 205564c00d81SAndrew Gallatin 20561da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20571da177e4SLinus Torvalds 2058f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 2059f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); 20601da177e4SLinus Torvalds 20611da177e4SLinus Torvalds /* Set up Dest MAC */ 2062f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 20631da177e4SLinus Torvalds 20641da177e4SLinus Torvalds /* Set up pkt size */ 20651da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 20661da177e4SLinus Torvalds 20671da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20681da177e4SLinus Torvalds /* 20691da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 20701da177e4SLinus Torvalds * gets exported 20711da177e4SLinus Torvalds */ 20721da177e4SLinus Torvalds 20731da177e4SLinus Torvalds #ifdef NOTNOW 20741da177e4SLinus Torvalds int i, set = 0, err = 1; 20751da177e4SLinus Torvalds struct inet6_dev *idev; 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20781da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20791da177e4SLinus Torvalds set = 1; 20801da177e4SLinus Torvalds break; 20811da177e4SLinus Torvalds } 20821da177e4SLinus Torvalds 20831da177e4SLinus Torvalds if (!set) { 20841da177e4SLinus Torvalds 20851da177e4SLinus Torvalds /* 20861da177e4SLinus Torvalds * Use linklevel address if unconfigured. 20871da177e4SLinus Torvalds * 20881da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 20891da177e4SLinus Torvalds */ 20901da177e4SLinus Torvalds 20918814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 209263adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 209363adc6fbSStephen Hemminger if (idev) { 20941da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 20951da177e4SLinus Torvalds 20961da177e4SLinus Torvalds read_lock_bh(&idev->lock); 2097222f1806SLuiz Capitulino for (ifp = idev->addr_list; ifp; 2098222f1806SLuiz Capitulino ifp = ifp->if_next) { 2099f64f9e71SJoe Perches if (ifp->scope == IFA_LINK && 2100f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 2101222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev-> 2102222f1806SLuiz Capitulino cur_in6_saddr, 2103222f1806SLuiz Capitulino &ifp->addr); 21041da177e4SLinus Torvalds err = 0; 21051da177e4SLinus Torvalds break; 21061da177e4SLinus Torvalds } 21071da177e4SLinus Torvalds } 21081da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 21091da177e4SLinus Torvalds } 21108814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2111222f1806SLuiz Capitulino if (err) 2112f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21131da177e4SLinus Torvalds } 21141da177e4SLinus Torvalds #endif 2115222f1806SLuiz Capitulino } else { 21161da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21171da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21181da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21191da177e4SLinus Torvalds 21201da177e4SLinus Torvalds struct in_device *in_dev; 21211da177e4SLinus Torvalds 21221da177e4SLinus Torvalds rcu_read_lock(); 2123e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21241da177e4SLinus Torvalds if (in_dev) { 21251da177e4SLinus Torvalds if (in_dev->ifa_list) { 2126222f1806SLuiz Capitulino pkt_dev->saddr_min = 2127222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 21281da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21291da177e4SLinus Torvalds } 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds rcu_read_unlock(); 2132222f1806SLuiz Capitulino } else { 21331da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21341da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21351da177e4SLinus Torvalds } 21361da177e4SLinus Torvalds 21371da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21381da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21391da177e4SLinus Torvalds } 21401da177e4SLinus Torvalds /* Initialize current values. */ 21411da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21421da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21431da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21441da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21451da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21461da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21471da177e4SLinus Torvalds pkt_dev->nflows = 0; 21481da177e4SLinus Torvalds } 21491da177e4SLinus Torvalds 21501da177e4SLinus Torvalds 2151fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2152fd29cf72SStephen Hemminger { 2153ef87979cSStephen Hemminger ktime_t start_time, end_time; 2154417bc4b8SEric Dumazet s64 remaining; 21552bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2156fd29cf72SStephen Hemminger 21572bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21582bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2159fd29cf72SStephen Hemminger 216043d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2161417bc4b8SEric Dumazet if (remaining <= 0) { 2162417bc4b8SEric Dumazet pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21631da177e4SLinus Torvalds return; 2164417bc4b8SEric Dumazet } 21652bc481cfSStephen Hemminger 2166ef87979cSStephen Hemminger start_time = ktime_now(); 216743d28b65SDaniel Turull if (remaining < 100000) 216843d28b65SDaniel Turull ndelay(remaining); /* really small just spin */ 21692bc481cfSStephen Hemminger else { 21702bc481cfSStephen Hemminger /* see do_nanosleep */ 21712bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 21722bc481cfSStephen Hemminger do { 21732bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21742bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 21752bc481cfSStephen Hemminger if (!hrtimer_active(&t.timer)) 21762bc481cfSStephen Hemminger t.task = NULL; 21772bc481cfSStephen Hemminger 21782bc481cfSStephen Hemminger if (likely(t.task)) 21791da177e4SLinus Torvalds schedule(); 21801da177e4SLinus Torvalds 21812bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 21822bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 21832bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 21841da177e4SLinus Torvalds } 2185ef87979cSStephen Hemminger end_time = ktime_now(); 2186ef87979cSStephen Hemminger 2187ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 218807a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21891da177e4SLinus Torvalds } 21901da177e4SLinus Torvalds 219116dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 219216dab72fSJamal Hadi Salim { 2193a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 219416dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 219516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 219616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 219716dab72fSJamal Hadi Salim } 219816dab72fSJamal Hadi Salim 2199648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2200007a531bSJamal Hadi Salim { 2201648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2202007a531bSJamal Hadi Salim } 2203007a531bSJamal Hadi Salim 2204007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2205007a531bSJamal Hadi Salim { 2206007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2207007a531bSJamal Hadi Salim 2208007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2209007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2210007a531bSJamal Hadi Salim /* reset time */ 2211007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22121211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2213007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2214007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2215007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2216007a531bSJamal Hadi Salim } 2217007a531bSJamal Hadi Salim } else { 2218007a531bSJamal Hadi Salim flow = random32() % pkt_dev->cflows; 22191211a645SRobert Olsson pkt_dev->curfl = flow; 2220007a531bSJamal Hadi Salim 22211211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2222007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22231211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22241211a645SRobert Olsson } 2225007a531bSJamal Hadi Salim } 2226007a531bSJamal Hadi Salim 2227007a531bSJamal Hadi Salim return pkt_dev->curfl; 2228007a531bSJamal Hadi Salim } 2229007a531bSJamal Hadi Salim 2230a553e4a6SJamal Hadi Salim 2231a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2232a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2233a553e4a6SJamal Hadi Salim * we go look for it ... 2234a553e4a6SJamal Hadi Salim */ 2235bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2236fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2237a553e4a6SJamal Hadi Salim { 2238a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 2239a553e4a6SJamal Hadi Salim if (!x) { 2240a553e4a6SJamal Hadi Salim /*slow path: we dont already have xfrm_state*/ 2241bd55775cSJamal Hadi Salim x = xfrm_stateonly_find(&init_net, DUMMY_MARK, 22425447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2243a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2244a553e4a6SJamal Hadi Salim AF_INET, 2245a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2246a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2247a553e4a6SJamal Hadi Salim if (x) { 2248a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2249a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2250a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2251a553e4a6SJamal Hadi Salim } 2252a553e4a6SJamal Hadi Salim 2253a553e4a6SJamal Hadi Salim } 2254a553e4a6SJamal Hadi Salim } 2255a553e4a6SJamal Hadi Salim #endif 2256fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2257fd2ea0a7SDavid S. Miller { 2258e6fce5b9SRobert Olsson 2259e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2260e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2261e6fce5b9SRobert Olsson 2262896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2263fd2ea0a7SDavid S. Miller __u16 t; 2264fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 2265fd2ea0a7SDavid S. Miller t = random32() % 2266fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2267fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2268fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2269fd2ea0a7SDavid S. Miller } else { 2270fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2271fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2272fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2273fd2ea0a7SDavid S. Miller } 2274fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2275fd2ea0a7SDavid S. Miller } 2276bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2277fd2ea0a7SDavid S. Miller } 2278fd2ea0a7SDavid S. Miller 22791da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 22801da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 22811da177e4SLinus Torvalds */ 2282222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2283222f1806SLuiz Capitulino { 22841da177e4SLinus Torvalds __u32 imn; 22851da177e4SLinus Torvalds __u32 imx; 22861da177e4SLinus Torvalds int flow = 0; 22871da177e4SLinus Torvalds 2288007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2289007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds /* Deal with source MAC */ 22921da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 22931da177e4SLinus Torvalds __u32 mc; 22941da177e4SLinus Torvalds __u32 tmp; 22951da177e4SLinus Torvalds 22961da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 22975fa6fc76SStephen Hemminger mc = random32() % pkt_dev->src_mac_count; 22981da177e4SLinus Torvalds else { 22991da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2300ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2301222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23021da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23031da177e4SLinus Torvalds } 23041da177e4SLinus Torvalds 23051da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23061da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23071da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23081da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23091da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23101da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23111da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23121da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23131da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23141da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23151da177e4SLinus Torvalds } 23161da177e4SLinus Torvalds 23171da177e4SLinus Torvalds /* Deal with Destination MAC */ 23181da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23191da177e4SLinus Torvalds __u32 mc; 23201da177e4SLinus Torvalds __u32 tmp; 23211da177e4SLinus Torvalds 23221da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 23235fa6fc76SStephen Hemminger mc = random32() % pkt_dev->dst_mac_count; 23241da177e4SLinus Torvalds 23251da177e4SLinus Torvalds else { 23261da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2327ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2328222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23291da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23301da177e4SLinus Torvalds } 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds 23331da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23341da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23351da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23361da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23371da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23381da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23391da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23401da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23411da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23421da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23431da177e4SLinus Torvalds } 23441da177e4SLinus Torvalds 2345ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 2346ca6549afSSteven Whitehouse unsigned i; 2347ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2348ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2349ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 23505fa6fc76SStephen Hemminger ((__force __be32)random32() & 2351ca6549afSSteven Whitehouse htonl(0x000fffff)); 2352ca6549afSSteven Whitehouse } 2353ca6549afSSteven Whitehouse 235434954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 23555fa6fc76SStephen Hemminger pkt_dev->vlan_id = random32() & (4096-1); 235634954ddcSFrancesco Fondelli } 235734954ddcSFrancesco Fondelli 235834954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 23595fa6fc76SStephen Hemminger pkt_dev->svlan_id = random32() & (4096 - 1); 236034954ddcSFrancesco Fondelli } 236134954ddcSFrancesco Fondelli 23621da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23631da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 23645fa6fc76SStephen Hemminger pkt_dev->cur_udp_src = random32() % 23655fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23665fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23671da177e4SLinus Torvalds 23681da177e4SLinus Torvalds else { 23691da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 23701da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23711da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23761da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 23775fa6fc76SStephen Hemminger pkt_dev->cur_udp_dst = random32() % 23785fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23795fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2380222f1806SLuiz Capitulino } else { 23811da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 23821da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 23831da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 23841da177e4SLinus Torvalds } 23851da177e4SLinus Torvalds } 23861da177e4SLinus Torvalds 23871da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 23881da177e4SLinus Torvalds 238963adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 239063adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 239163adc6fbSStephen Hemminger if (imn < imx) { 23921da177e4SLinus Torvalds __u32 t; 23931da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 23945fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 23951da177e4SLinus Torvalds else { 23961da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 23971da177e4SLinus Torvalds t++; 239863adc6fbSStephen Hemminger if (t > imx) 23991da177e4SLinus Torvalds t = imn; 240063adc6fbSStephen Hemminger 24011da177e4SLinus Torvalds } 24021da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds 2405007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24061da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24071da177e4SLinus Torvalds } else { 2408252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2409252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2410252e3346SAl Viro if (imn < imx) { 24111da177e4SLinus Torvalds __u32 t; 2412252e3346SAl Viro __be32 s; 24131da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24141da177e4SLinus Torvalds 24155fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2416252e3346SAl Viro s = htonl(t); 24171da177e4SLinus Torvalds 241821cf2253SJoe Perches while (ipv4_is_loopback(s) || 241921cf2253SJoe Perches ipv4_is_multicast(s) || 24201e637c74SJan Engelhardt ipv4_is_lbcast(s) || 242121cf2253SJoe Perches ipv4_is_zeronet(s) || 242221cf2253SJoe Perches ipv4_is_local_multicast(s)) { 24235fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2424252e3346SAl Viro s = htonl(t); 24251da177e4SLinus Torvalds } 2426252e3346SAl Viro pkt_dev->cur_daddr = s; 2427252e3346SAl Viro } else { 24281da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24291da177e4SLinus Torvalds t++; 24301da177e4SLinus Torvalds if (t > imx) { 24311da177e4SLinus Torvalds t = imn; 24321da177e4SLinus Torvalds } 24331da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24341da177e4SLinus Torvalds } 24351da177e4SLinus Torvalds } 24361da177e4SLinus Torvalds if (pkt_dev->cflows) { 2437007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2438222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2439222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2440a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2441a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2442a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2443a553e4a6SJamal Hadi Salim #endif 24441da177e4SLinus Torvalds pkt_dev->nflows++; 24451da177e4SLinus Torvalds } 24461da177e4SLinus Torvalds } 2447222f1806SLuiz Capitulino } else { /* IPV6 * */ 2448222f1806SLuiz Capitulino 24491da177e4SLinus Torvalds if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 24501da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 24511da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 24521da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; 24531da177e4SLinus Torvalds else { 24541da177e4SLinus Torvalds int i; 24551da177e4SLinus Torvalds 24561da177e4SLinus Torvalds /* Only random destinations yet */ 24571da177e4SLinus Torvalds 24581da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24591da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 24605fa6fc76SStephen Hemminger (((__force __be32)random32() | 24611da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24621da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24631da177e4SLinus Torvalds } 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds 24671da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24681da177e4SLinus Torvalds __u32 t; 24691da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 24705fa6fc76SStephen Hemminger t = random32() % 24715fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24725fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2473222f1806SLuiz Capitulino } else { 24741da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 24751da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 24761da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 24771da177e4SLinus Torvalds } 24781da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 24791da177e4SLinus Torvalds } 24801da177e4SLinus Torvalds 2481fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 248245b270f8SRobert Olsson 24831da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 24841da177e4SLinus Torvalds } 24851da177e4SLinus Torvalds 2486a553e4a6SJamal Hadi Salim 2487a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2488a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2489a553e4a6SJamal Hadi Salim { 2490a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2491a553e4a6SJamal Hadi Salim int err = 0; 2492a553e4a6SJamal Hadi Salim struct iphdr *iph; 2493a553e4a6SJamal Hadi Salim 2494a553e4a6SJamal Hadi Salim if (!x) 2495a553e4a6SJamal Hadi Salim return 0; 2496a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2497a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2498a553e4a6SJamal Hadi Salim if (x->props.mode != XFRM_MODE_TRANSPORT) 2499a553e4a6SJamal Hadi Salim return 0; 2500a553e4a6SJamal Hadi Salim 2501a553e4a6SJamal Hadi Salim spin_lock(&x->lock); 2502a553e4a6SJamal Hadi Salim iph = ip_hdr(skb); 2503a553e4a6SJamal Hadi Salim 250413996378SHerbert Xu err = x->outer_mode->output(x, skb); 2505a553e4a6SJamal Hadi Salim if (err) 2506a553e4a6SJamal Hadi Salim goto error; 2507a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 2508a553e4a6SJamal Hadi Salim if (err) 2509a553e4a6SJamal Hadi Salim goto error; 2510a553e4a6SJamal Hadi Salim 2511a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2512a553e4a6SJamal Hadi Salim x->curlft.packets++; 2513a553e4a6SJamal Hadi Salim error: 2514a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2515a553e4a6SJamal Hadi Salim return err; 2516a553e4a6SJamal Hadi Salim } 2517a553e4a6SJamal Hadi Salim 2518475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2519a553e4a6SJamal Hadi Salim { 2520a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2521a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2522a553e4a6SJamal Hadi Salim int i = 0; 25235b5f792aSFlorian Westphal for (; i < pkt_dev->cflows; i++) { 2524a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2525a553e4a6SJamal Hadi Salim if (x) { 2526a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2527a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2528a553e4a6SJamal Hadi Salim } 2529a553e4a6SJamal Hadi Salim } 2530a553e4a6SJamal Hadi Salim } 2531a553e4a6SJamal Hadi Salim } 2532a553e4a6SJamal Hadi Salim 2533475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2534a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2535a553e4a6SJamal Hadi Salim { 2536a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2537a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2538a553e4a6SJamal Hadi Salim int nhead = 0; 2539a553e4a6SJamal Hadi Salim if (x) { 2540a553e4a6SJamal Hadi Salim int ret; 2541a553e4a6SJamal Hadi Salim __u8 *eth; 2542a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2543a553e4a6SJamal Hadi Salim if (nhead > 0) { 2544a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2545a553e4a6SJamal Hadi Salim if (ret < 0) { 2546f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2547f9467eaeSJoe Perches ret); 2548b4bb4ac8SIlpo Järvinen goto err; 2549a553e4a6SJamal Hadi Salim } 2550a553e4a6SJamal Hadi Salim } 2551a553e4a6SJamal Hadi Salim 2552a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2553a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2554a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2555a553e4a6SJamal Hadi Salim if (ret) { 2556f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2557b4bb4ac8SIlpo Järvinen goto err; 2558a553e4a6SJamal Hadi Salim } 2559a553e4a6SJamal Hadi Salim /* restore ll */ 2560a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2561a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2562a553e4a6SJamal Hadi Salim *(u16 *) ð[12] = protocol; 2563a553e4a6SJamal Hadi Salim } 2564a553e4a6SJamal Hadi Salim } 2565a553e4a6SJamal Hadi Salim return 1; 2566b4bb4ac8SIlpo Järvinen err: 2567b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2568b4bb4ac8SIlpo Järvinen return 0; 2569a553e4a6SJamal Hadi Salim } 2570a553e4a6SJamal Hadi Salim #endif 2571a553e4a6SJamal Hadi Salim 2572ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2573ca6549afSSteven Whitehouse { 2574ca6549afSSteven Whitehouse unsigned i; 257563adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2576ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 257763adc6fbSStephen Hemminger 2578ca6549afSSteven Whitehouse mpls--; 2579ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2580ca6549afSSteven Whitehouse } 2581ca6549afSSteven Whitehouse 25820f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 25830f37c605SAl Viro unsigned int prio) 25840f37c605SAl Viro { 25850f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 25860f37c605SAl Viro } 25870f37c605SAl Viro 25881da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 25891da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 25901da177e4SLinus Torvalds { 25911da177e4SLinus Torvalds struct sk_buff *skb = NULL; 25921da177e4SLinus Torvalds __u8 *eth; 25931da177e4SLinus Torvalds struct udphdr *udph; 25941da177e4SLinus Torvalds int datalen, iplen; 25951da177e4SLinus Torvalds struct iphdr *iph; 25961da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2597d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2598ca6549afSSteven Whitehouse __be32 *mpls; 259934954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 260034954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 260134954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 260234954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2603fd2ea0a7SDavid S. Miller u16 queue_map; 2604ca6549afSSteven Whitehouse 2605ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2606d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 26071da177e4SLinus Torvalds 260834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2609d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 261034954ddcSFrancesco Fondelli 261164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 261264053beeSRobert Olsson * fields. 261364053beeSRobert Olsson */ 2614fd2ea0a7SDavid S. Miller queue_map = pkt_dev->cur_queue_map; 261564053beeSRobert Olsson mod_cur_headers(pkt_dev); 261664053beeSRobert Olsson 26177ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2618e99b99b4SRobert Olsson 2619e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) { 2620e99b99b4SRobert Olsson int node; 2621e99b99b4SRobert Olsson 2622e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 2623e99b99b4SRobert Olsson node = pkt_dev->node; 2624e99b99b4SRobert Olsson else 2625e99b99b4SRobert Olsson node = numa_node_id(); 2626e99b99b4SRobert Olsson 2627e99b99b4SRobert Olsson skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64 2628e99b99b4SRobert Olsson + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node); 2629e99b99b4SRobert Olsson if (likely(skb)) { 2630e99b99b4SRobert Olsson skb_reserve(skb, NET_SKB_PAD); 2631e99b99b4SRobert Olsson skb->dev = odev; 2632e99b99b4SRobert Olsson } 2633e99b99b4SRobert Olsson } 2634e99b99b4SRobert Olsson else 2635e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2636e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2637e470757dSStephen Hemminger + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); 2638e99b99b4SRobert Olsson 26391da177e4SLinus Torvalds if (!skb) { 26401da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 26411da177e4SLinus Torvalds return NULL; 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds 26447ac5459eSDavid S. Miller skb_reserve(skb, datalen); 26451da177e4SLinus Torvalds 26461da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 26471da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2648ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2649ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2650ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 265134954ddcSFrancesco Fondelli 265234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 265334954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 265434954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26550f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 26560f37c605SAl Viro pkt_dev->svlan_cfi, 26570f37c605SAl Viro pkt_dev->svlan_p); 265834954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2659d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 266034954ddcSFrancesco Fondelli } 266134954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26620f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 26630f37c605SAl Viro pkt_dev->vlan_cfi, 26640f37c605SAl Viro pkt_dev->vlan_p); 266534954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2666d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 266734954ddcSFrancesco Fondelli } 266834954ddcSFrancesco Fondelli 266927a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2670b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct iphdr); 2671ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2672fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 2673ddc7b8e3SArnaldo Carvalho de Melo iph = ip_hdr(skb); 2674ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 26751da177e4SLinus Torvalds 26761da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2677252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 26781da177e4SLinus Torvalds 2679ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2680ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 268116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 26821da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 26831da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 26841da177e4SLinus Torvalds 26851da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 26861da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 26871da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 26881da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 26891da177e4SLinus Torvalds 26901da177e4SLinus Torvalds iph->ihl = 5; 26911da177e4SLinus Torvalds iph->version = 4; 26921da177e4SLinus Torvalds iph->ttl = 32; 26931ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 26941da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 26951da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 26961da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 269766ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 269866ed1e5eSEric Dumazet pkt_dev->ip_id++; 26991da177e4SLinus Torvalds iph->frag_off = 0; 27001da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 27011da177e4SLinus Torvalds iph->tot_len = htons(iplen); 27021da177e4SLinus Torvalds iph->check = 0; 27031da177e4SLinus Torvalds iph->check = ip_fast_csum((void *)iph, iph->ihl); 2704ca6549afSSteven Whitehouse skb->protocol = protocol; 2705b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 270616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 27071da177e4SLinus Torvalds skb->dev = odev; 27081da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 27091da177e4SLinus Torvalds 271066ed1e5eSEric Dumazet if (pkt_dev->nfrags <= 0) { 27111da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 271266ed1e5eSEric Dumazet memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); 271366ed1e5eSEric Dumazet } else { 27141da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 271566ed1e5eSEric Dumazet int i, len; 27161da177e4SLinus Torvalds 27171da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 27181da177e4SLinus Torvalds 27191da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 27201da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 27211da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 272266ed1e5eSEric Dumazet len = datalen - frags * PAGE_SIZE; 272366ed1e5eSEric Dumazet memset(skb_put(skb, len), 0, len); 27241da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 27251da177e4SLinus Torvalds } 27261da177e4SLinus Torvalds 27271da177e4SLinus Torvalds i = 0; 27281da177e4SLinus Torvalds while (datalen > 0) { 272966ed1e5eSEric Dumazet struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); 27301da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 27311da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 27321da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 27331da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 27341da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 27351da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 27361da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 27371da177e4SLinus Torvalds i++; 27381da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27391da177e4SLinus Torvalds } 27401da177e4SLinus Torvalds 27411da177e4SLinus Torvalds while (i < frags) { 27421da177e4SLinus Torvalds int rem; 27431da177e4SLinus Torvalds 27441da177e4SLinus Torvalds if (i == 0) 27451da177e4SLinus Torvalds break; 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 27481da177e4SLinus Torvalds if (rem == 0) 27491da177e4SLinus Torvalds break; 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 27521da177e4SLinus Torvalds 2753222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2754222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 27551da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2756222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2757222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2758222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2759222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 27601da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 27611da177e4SLinus Torvalds i++; 27621da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27631da177e4SLinus Torvalds } 27641da177e4SLinus Torvalds } 27651da177e4SLinus Torvalds 276663adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 276763adc6fbSStephen Hemminger * convert them to network byte order 276863adc6fbSStephen Hemminger */ 27691da177e4SLinus Torvalds if (pgh) { 27701da177e4SLinus Torvalds struct timeval timestamp; 27711da177e4SLinus Torvalds 27721da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 27731da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 27741da177e4SLinus Torvalds 27751da177e4SLinus Torvalds do_gettimeofday(×tamp); 27761da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 27771da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 27781da177e4SLinus Torvalds } 27791da177e4SLinus Torvalds 2780a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2781a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2782a553e4a6SJamal Hadi Salim return NULL; 2783a553e4a6SJamal Hadi Salim #endif 2784a553e4a6SJamal Hadi Salim 27851da177e4SLinus Torvalds return skb; 27861da177e4SLinus Torvalds } 27871da177e4SLinus Torvalds 27881da177e4SLinus Torvalds /* 27891da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 27901da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 27911da177e4SLinus Torvalds * 27921da177e4SLinus Torvalds * Slightly modified for kernel. 27931da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 27941da177e4SLinus Torvalds * --ro 27951da177e4SLinus Torvalds */ 27961da177e4SLinus Torvalds 27971da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]) 27981da177e4SLinus Torvalds { 27991da177e4SLinus Torvalds unsigned int i; 28001da177e4SLinus Torvalds unsigned int len = 0; 28011da177e4SLinus Torvalds unsigned long u; 28021da177e4SLinus Torvalds char suffix[16]; 28031da177e4SLinus Torvalds unsigned int prefixlen = 0; 28041da177e4SLinus Torvalds unsigned int suffixlen = 0; 2805252e3346SAl Viro __be32 tmp; 2806cfcabdccSStephen Hemminger char *pos; 28071da177e4SLinus Torvalds 2808222f1806SLuiz Capitulino for (i = 0; i < 16; i++) 2809222f1806SLuiz Capitulino ip[i] = 0; 28101da177e4SLinus Torvalds 28111da177e4SLinus Torvalds for (;;) { 28121da177e4SLinus Torvalds if (*s == ':') { 28131da177e4SLinus Torvalds len++; 28141da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 28151da177e4SLinus Torvalds s += 2; 28161da177e4SLinus Torvalds len++; 28171da177e4SLinus Torvalds break; 28181da177e4SLinus Torvalds } 28191da177e4SLinus Torvalds s++; 28201da177e4SLinus Torvalds } 28211da177e4SLinus Torvalds 2822cfcabdccSStephen Hemminger u = simple_strtoul(s, &pos, 16); 2823cfcabdccSStephen Hemminger i = pos - s; 2824222f1806SLuiz Capitulino if (!i) 2825222f1806SLuiz Capitulino return 0; 28261da177e4SLinus Torvalds if (prefixlen == 12 && s[i] == '.') { 28271da177e4SLinus Torvalds 28281da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 28291da177e4SLinus Torvalds 28301da177e4SLinus Torvalds tmp = in_aton(s); 28311da177e4SLinus Torvalds memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); 28321da177e4SLinus Torvalds return i + len; 28331da177e4SLinus Torvalds } 28341da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 28351da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2836222f1806SLuiz Capitulino s += i; 2837222f1806SLuiz Capitulino len += i; 28381da177e4SLinus Torvalds if (prefixlen == 16) 28391da177e4SLinus Torvalds return len; 28401da177e4SLinus Torvalds } 28411da177e4SLinus Torvalds 28421da177e4SLinus Torvalds /* part 2, after "::" */ 28431da177e4SLinus Torvalds for (;;) { 28441da177e4SLinus Torvalds if (*s == ':') { 28451da177e4SLinus Torvalds if (suffixlen == 0) 28461da177e4SLinus Torvalds break; 28471da177e4SLinus Torvalds s++; 28481da177e4SLinus Torvalds len++; 28491da177e4SLinus Torvalds } else if (suffixlen != 0) 28501da177e4SLinus Torvalds break; 2851cfcabdccSStephen Hemminger 2852cfcabdccSStephen Hemminger u = simple_strtol(s, &pos, 16); 2853cfcabdccSStephen Hemminger i = pos - s; 28541da177e4SLinus Torvalds if (!i) { 2855222f1806SLuiz Capitulino if (*s) 2856222f1806SLuiz Capitulino len--; 28571da177e4SLinus Torvalds break; 28581da177e4SLinus Torvalds } 28591da177e4SLinus Torvalds if (suffixlen + prefixlen <= 12 && s[i] == '.') { 28601da177e4SLinus Torvalds tmp = in_aton(s); 2861222f1806SLuiz Capitulino memcpy((struct in_addr *)(suffix + suffixlen), &tmp, 2862222f1806SLuiz Capitulino sizeof(tmp)); 28631da177e4SLinus Torvalds suffixlen += 4; 28641da177e4SLinus Torvalds len += strlen(s); 28651da177e4SLinus Torvalds break; 28661da177e4SLinus Torvalds } 28671da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 28681da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2869222f1806SLuiz Capitulino s += i; 2870222f1806SLuiz Capitulino len += i; 28711da177e4SLinus Torvalds if (prefixlen + suffixlen == 16) 28721da177e4SLinus Torvalds break; 28731da177e4SLinus Torvalds } 28741da177e4SLinus Torvalds for (i = 0; i < suffixlen; i++) 28751da177e4SLinus Torvalds ip[16 - suffixlen + i] = suffix[i]; 28761da177e4SLinus Torvalds return len; 28771da177e4SLinus Torvalds } 28781da177e4SLinus Torvalds 2879222f1806SLuiz Capitulino static char tohex(char hexdigit) 2880222f1806SLuiz Capitulino { 28811da177e4SLinus Torvalds return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; 28821da177e4SLinus Torvalds } 28831da177e4SLinus Torvalds 2884222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i) 2885222f1806SLuiz Capitulino { 28861da177e4SLinus Torvalds char *bak = s; 2887222f1806SLuiz Capitulino *s = tohex((i >> 12) & 0xf); 2888222f1806SLuiz Capitulino if (s != bak || *s != '0') 2889222f1806SLuiz Capitulino ++s; 2890222f1806SLuiz Capitulino *s = tohex((i >> 8) & 0xf); 2891222f1806SLuiz Capitulino if (s != bak || *s != '0') 2892222f1806SLuiz Capitulino ++s; 2893222f1806SLuiz Capitulino *s = tohex((i >> 4) & 0xf); 2894222f1806SLuiz Capitulino if (s != bak || *s != '0') 2895222f1806SLuiz Capitulino ++s; 28961da177e4SLinus Torvalds *s = tohex(i & 0xf); 28971da177e4SLinus Torvalds return s - bak + 1; 28981da177e4SLinus Torvalds } 28991da177e4SLinus Torvalds 2900222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16]) 2901222f1806SLuiz Capitulino { 29021da177e4SLinus Torvalds unsigned int len; 29031da177e4SLinus Torvalds unsigned int i; 29041da177e4SLinus Torvalds unsigned int temp; 29051da177e4SLinus Torvalds unsigned int compressing; 29061da177e4SLinus Torvalds int j; 29071da177e4SLinus Torvalds 2908222f1806SLuiz Capitulino len = 0; 2909222f1806SLuiz Capitulino compressing = 0; 29101da177e4SLinus Torvalds for (j = 0; j < 16; j += 2) { 29111da177e4SLinus Torvalds 29121da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 29131da177e4SLinus Torvalds if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { 29141da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr *)(ip + 12), s); 29151da177e4SLinus Torvalds temp = strlen(s); 29161da177e4SLinus Torvalds return len + temp; 29171da177e4SLinus Torvalds } 29181da177e4SLinus Torvalds #endif 29191da177e4SLinus Torvalds temp = ((unsigned long)(unsigned char)ip[j] << 8) + 29201da177e4SLinus Torvalds (unsigned long)(unsigned char)ip[j + 1]; 29211da177e4SLinus Torvalds if (temp == 0) { 29221da177e4SLinus Torvalds if (!compressing) { 29231da177e4SLinus Torvalds compressing = 1; 29241da177e4SLinus Torvalds if (j == 0) { 2925222f1806SLuiz Capitulino *s++ = ':'; 2926222f1806SLuiz Capitulino ++len; 29271da177e4SLinus Torvalds } 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds } else { 29301da177e4SLinus Torvalds if (compressing) { 29311da177e4SLinus Torvalds compressing = 0; 2932222f1806SLuiz Capitulino *s++ = ':'; 2933222f1806SLuiz Capitulino ++len; 29341da177e4SLinus Torvalds } 2935222f1806SLuiz Capitulino i = fmt_xlong(s, temp); 2936222f1806SLuiz Capitulino len += i; 2937222f1806SLuiz Capitulino s += i; 29381da177e4SLinus Torvalds if (j < 14) { 29391da177e4SLinus Torvalds *s++ = ':'; 29401da177e4SLinus Torvalds ++len; 29411da177e4SLinus Torvalds } 29421da177e4SLinus Torvalds } 29431da177e4SLinus Torvalds } 29441da177e4SLinus Torvalds if (compressing) { 2945222f1806SLuiz Capitulino *s++ = ':'; 2946222f1806SLuiz Capitulino ++len; 29471da177e4SLinus Torvalds } 29481da177e4SLinus Torvalds *s = 0; 29491da177e4SLinus Torvalds return len; 29501da177e4SLinus Torvalds } 29511da177e4SLinus Torvalds 29521da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29531da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29541da177e4SLinus Torvalds { 29551da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29561da177e4SLinus Torvalds __u8 *eth; 29571da177e4SLinus Torvalds struct udphdr *udph; 29581da177e4SLinus Torvalds int datalen; 29591da177e4SLinus Torvalds struct ipv6hdr *iph; 29601da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2961d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2962ca6549afSSteven Whitehouse __be32 *mpls; 296334954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 296434954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 296534954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 296634954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2967fd2ea0a7SDavid S. Miller u16 queue_map; 2968ca6549afSSteven Whitehouse 2969ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2970d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 29711da177e4SLinus Torvalds 297234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2973d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 297434954ddcSFrancesco Fondelli 297564053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 297664053beeSRobert Olsson * fields. 297764053beeSRobert Olsson */ 2978fd2ea0a7SDavid S. Miller queue_map = pkt_dev->cur_queue_map; 297964053beeSRobert Olsson mod_cur_headers(pkt_dev); 298064053beeSRobert Olsson 2981e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2982e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2983e470757dSStephen Hemminger + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT); 29841da177e4SLinus Torvalds if (!skb) { 29851da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 29861da177e4SLinus Torvalds return NULL; 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds 29891da177e4SLinus Torvalds skb_reserve(skb, 16); 29901da177e4SLinus Torvalds 29911da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 29921da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2993ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2994ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2995ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 299634954ddcSFrancesco Fondelli 299734954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 299834954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 299934954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30000f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30010f37c605SAl Viro pkt_dev->svlan_cfi, 30020f37c605SAl Viro pkt_dev->svlan_p); 300334954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3004d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 300534954ddcSFrancesco Fondelli } 300634954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30070f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30080f37c605SAl Viro pkt_dev->vlan_cfi, 30090f37c605SAl Viro pkt_dev->vlan_p); 301034954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3011d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 301234954ddcSFrancesco Fondelli } 301334954ddcSFrancesco Fondelli 301427a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 3015b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 3016ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 3017fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 3018ddc7b8e3SArnaldo Carvalho de Melo iph = ipv6_hdr(skb); 3019ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 30201da177e4SLinus Torvalds 30211da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3022252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30231da177e4SLinus Torvalds 3024ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3025ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3026ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 302716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 30301da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 30311da177e4SLinus Torvalds if (net_ratelimit()) 3032f9467eaeSJoe Perches pr_info("increased datalen to %d\n", datalen); 30331da177e4SLinus Torvalds } 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30361da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 30371da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 30381da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 30391da177e4SLinus Torvalds 3040d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30411da177e4SLinus Torvalds 30421ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30431ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3044252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30451ca7768cSFrancesco Fondelli } 30461ca7768cSFrancesco Fondelli 30471da177e4SLinus Torvalds iph->hop_limit = 32; 30481da177e4SLinus Torvalds 30491da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 30501da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30511da177e4SLinus Torvalds 30521da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 30531da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 30541da177e4SLinus Torvalds 3055b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 305616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 3057ca6549afSSteven Whitehouse skb->protocol = protocol; 30581da177e4SLinus Torvalds skb->dev = odev; 30591da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30601da177e4SLinus Torvalds 30611da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 30621da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 30631da177e4SLinus Torvalds else { 30641da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 30651da177e4SLinus Torvalds int i; 30661da177e4SLinus Torvalds 30671da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 30681da177e4SLinus Torvalds 30691da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 30701da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 30711da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 30721da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 30731da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 30741da177e4SLinus Torvalds } 30751da177e4SLinus Torvalds 30761da177e4SLinus Torvalds i = 0; 30771da177e4SLinus Torvalds while (datalen > 0) { 30781da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 30791da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 30801da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 30811da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 30821da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 30831da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 30841da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 30851da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 30861da177e4SLinus Torvalds i++; 30871da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 30881da177e4SLinus Torvalds } 30891da177e4SLinus Torvalds 30901da177e4SLinus Torvalds while (i < frags) { 30911da177e4SLinus Torvalds int rem; 30921da177e4SLinus Torvalds 30931da177e4SLinus Torvalds if (i == 0) 30941da177e4SLinus Torvalds break; 30951da177e4SLinus Torvalds 30961da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 30971da177e4SLinus Torvalds if (rem == 0) 30981da177e4SLinus Torvalds break; 30991da177e4SLinus Torvalds 31001da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 31011da177e4SLinus Torvalds 3102222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 3103222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 31041da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 3105222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 3106222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 3107222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 3108222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 31091da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 31101da177e4SLinus Torvalds i++; 31111da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31121da177e4SLinus Torvalds } 31131da177e4SLinus Torvalds } 31141da177e4SLinus Torvalds 311563adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 311663adc6fbSStephen Hemminger * convert them to network byte order 311763adc6fbSStephen Hemminger * should we update cloned packets too ? 311863adc6fbSStephen Hemminger */ 31191da177e4SLinus Torvalds if (pgh) { 31201da177e4SLinus Torvalds struct timeval timestamp; 31211da177e4SLinus Torvalds 31221da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 31231da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 31241da177e4SLinus Torvalds 31251da177e4SLinus Torvalds do_gettimeofday(×tamp); 31261da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 31271da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 31281da177e4SLinus Torvalds } 312934954ddcSFrancesco Fondelli /* pkt_dev->seq_num++; FF: you really mean this? */ 31301da177e4SLinus Torvalds 31311da177e4SLinus Torvalds return skb; 31321da177e4SLinus Torvalds } 31331da177e4SLinus Torvalds 3134475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 31351da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 31361da177e4SLinus Torvalds { 31371da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 31381da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 31391da177e4SLinus Torvalds else 31401da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 31411da177e4SLinus Torvalds } 31421da177e4SLinus Torvalds 31431da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 31441da177e4SLinus Torvalds { 31451da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31461da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31471da177e4SLinus Torvalds pkt_dev->sofar = 0; 31481da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31491da177e4SLinus Torvalds pkt_dev->errors = 0; 31501da177e4SLinus Torvalds } 31511da177e4SLinus Torvalds 31521da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31531da177e4SLinus Torvalds 31541da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31551da177e4SLinus Torvalds { 3156c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31571da177e4SLinus Torvalds int started = 0; 31581da177e4SLinus Torvalds 3159f9467eaeSJoe Perches func_enter(); 31601da177e4SLinus Torvalds 31611da177e4SLinus Torvalds if_lock(t); 3162c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds /* 31651da177e4SLinus Torvalds * setup odev and create initial packet. 31661da177e4SLinus Torvalds */ 31671da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31681da177e4SLinus Torvalds 31691da177e4SLinus Torvalds if (pkt_dev->odev) { 31701da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31711da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 31721da177e4SLinus Torvalds pkt_dev->skb = NULL; 3173fd29cf72SStephen Hemminger pkt_dev->started_at = 3174fd29cf72SStephen Hemminger pkt_dev->next_tx = ktime_now(); 3175fd29cf72SStephen Hemminger 317616dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 31771da177e4SLinus Torvalds 31781da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 31791da177e4SLinus Torvalds started++; 3180222f1806SLuiz Capitulino } else 31811da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 31821da177e4SLinus Torvalds } 31831da177e4SLinus Torvalds if_unlock(t); 3184222f1806SLuiz Capitulino if (started) 3185222f1806SLuiz Capitulino t->control &= ~(T_STOP); 31861da177e4SLinus Torvalds } 31871da177e4SLinus Torvalds 31881da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 31891da177e4SLinus Torvalds { 3190cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31911da177e4SLinus Torvalds 3192f9467eaeSJoe Perches func_enter(); 31931da177e4SLinus Torvalds 31946146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3195cdcdbe0bSLuiz Capitulino 3196cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 319795ed63f7SArthur Kepner t->control |= T_STOP; 3198cdcdbe0bSLuiz Capitulino 31996146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32001da177e4SLinus Torvalds } 32011da177e4SLinus Torvalds 3202648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 32031da177e4SLinus Torvalds { 3204648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 32051da177e4SLinus Torvalds 3206c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 3207648fda74SStephen Hemminger if (pkt_dev->running) 3208648fda74SStephen Hemminger return 1; 3209648fda74SStephen Hemminger return 0; 32101da177e4SLinus Torvalds } 32111da177e4SLinus Torvalds 32121da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 32131da177e4SLinus Torvalds { 32141da177e4SLinus Torvalds if_lock(t); 32151da177e4SLinus Torvalds 32161da177e4SLinus Torvalds while (thread_is_running(t)) { 32171da177e4SLinus Torvalds 32181da177e4SLinus Torvalds if_unlock(t); 32191da177e4SLinus Torvalds 32201da177e4SLinus Torvalds msleep_interruptible(100); 32211da177e4SLinus Torvalds 32221da177e4SLinus Torvalds if (signal_pending(current)) 32231da177e4SLinus Torvalds goto signal; 32241da177e4SLinus Torvalds if_lock(t); 32251da177e4SLinus Torvalds } 32261da177e4SLinus Torvalds if_unlock(t); 32271da177e4SLinus Torvalds return 1; 32281da177e4SLinus Torvalds signal: 32291da177e4SLinus Torvalds return 0; 32301da177e4SLinus Torvalds } 32311da177e4SLinus Torvalds 32321da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 32331da177e4SLinus Torvalds { 3234cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32351da177e4SLinus Torvalds int sig = 1; 32361da177e4SLinus Torvalds 32376146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3238cdcdbe0bSLuiz Capitulino 3239cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 32401da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3241222f1806SLuiz Capitulino if (sig == 0) 3242222f1806SLuiz Capitulino break; 32431da177e4SLinus Torvalds } 3244cdcdbe0bSLuiz Capitulino 3245cdcdbe0bSLuiz Capitulino if (sig == 0) 3246cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32471da177e4SLinus Torvalds t->control |= (T_STOP); 3248cdcdbe0bSLuiz Capitulino 32496146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32501da177e4SLinus Torvalds return sig; 32511da177e4SLinus Torvalds } 32521da177e4SLinus Torvalds 32531da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 32541da177e4SLinus Torvalds { 3255cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32561da177e4SLinus Torvalds 3257f9467eaeSJoe Perches func_enter(); 32581da177e4SLinus Torvalds 32596146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 32601da177e4SLinus Torvalds 3261cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32621da177e4SLinus Torvalds t->control |= (T_RUN); 3263cdcdbe0bSLuiz Capitulino 32646146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32651da177e4SLinus Torvalds 326663adc6fbSStephen Hemminger /* Propagate thread->control */ 326763adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32681da177e4SLinus Torvalds 32691da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 32701da177e4SLinus Torvalds } 32711da177e4SLinus Torvalds 3272eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void) 3273eb37b41cSJesse Brandeburg { 3274eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3275eb37b41cSJesse Brandeburg 3276f9467eaeSJoe Perches func_enter(); 3277eb37b41cSJesse Brandeburg 3278eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3279eb37b41cSJesse Brandeburg 3280eb37b41cSJesse Brandeburg list_for_each_entry(t, &pktgen_threads, th_list) 3281eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3282eb37b41cSJesse Brandeburg 3283eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3284eb37b41cSJesse Brandeburg 328563adc6fbSStephen Hemminger /* Propagate thread->control */ 328663adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3287eb37b41cSJesse Brandeburg 3288eb37b41cSJesse Brandeburg pktgen_wait_all_threads_run(); 3289eb37b41cSJesse Brandeburg } 3290eb37b41cSJesse Brandeburg 32911da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 32921da177e4SLinus Torvalds { 3293fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 32941da177e4SLinus Torvalds char *p = pkt_dev->result; 3295fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3296fd29cf72SStephen Hemminger pkt_dev->started_at); 3297fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 32981da177e4SLinus Torvalds 3299fd29cf72SStephen Hemminger p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", 3300fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3301fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3302fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 33031da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 33041da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 33051da177e4SLinus Torvalds 3306fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3307fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 33081da177e4SLinus Torvalds 33091da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 33101da177e4SLinus Torvalds 33111da177e4SLinus Torvalds mbps = bps; 33121da177e4SLinus Torvalds do_div(mbps, 1000000); 33131da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 33141da177e4SLinus Torvalds (unsigned long long)pps, 33151da177e4SLinus Torvalds (unsigned long long)mbps, 33161da177e4SLinus Torvalds (unsigned long long)bps, 33171da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 33181da177e4SLinus Torvalds } 33191da177e4SLinus Torvalds 33201da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 33211da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 33221da177e4SLinus Torvalds { 3323222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 33241da177e4SLinus Torvalds 33251da177e4SLinus Torvalds if (!pkt_dev->running) { 3326f9467eaeSJoe Perches pr_warning("interface: %s is already stopped\n", 3327f9467eaeSJoe Perches pkt_dev->odevname); 33281da177e4SLinus Torvalds return -EINVAL; 33291da177e4SLinus Torvalds } 33301da177e4SLinus Torvalds 33313bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 33323bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3333fd29cf72SStephen Hemminger pkt_dev->stopped_at = ktime_now(); 33341da177e4SLinus Torvalds pkt_dev->running = 0; 33351da177e4SLinus Torvalds 333695ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 33371da177e4SLinus Torvalds 33381da177e4SLinus Torvalds return 0; 33391da177e4SLinus Torvalds } 33401da177e4SLinus Torvalds 33411da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 33421da177e4SLinus Torvalds { 3343c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 33441da177e4SLinus Torvalds 33451da177e4SLinus Torvalds if_lock(t); 33461da177e4SLinus Torvalds 3347c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3348c26a8016SLuiz Capitulino if (!pkt_dev->running) 3349222f1806SLuiz Capitulino continue; 3350222f1806SLuiz Capitulino if (best == NULL) 3351c26a8016SLuiz Capitulino best = pkt_dev; 3352fd29cf72SStephen Hemminger else if (ktime_lt(pkt_dev->next_tx, best->next_tx)) 3353c26a8016SLuiz Capitulino best = pkt_dev; 33541da177e4SLinus Torvalds } 33551da177e4SLinus Torvalds if_unlock(t); 33561da177e4SLinus Torvalds return best; 33571da177e4SLinus Torvalds } 33581da177e4SLinus Torvalds 3359222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3360222f1806SLuiz Capitulino { 3361c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33621da177e4SLinus Torvalds 3363f9467eaeSJoe Perches func_enter(); 33641da177e4SLinus Torvalds 33651da177e4SLinus Torvalds if_lock(t); 33661da177e4SLinus Torvalds 3367c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3368c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 336995ed63f7SArthur Kepner } 337095ed63f7SArthur Kepner 337195ed63f7SArthur Kepner if_unlock(t); 337295ed63f7SArthur Kepner } 337395ed63f7SArthur Kepner 337495ed63f7SArthur Kepner /* 337595ed63f7SArthur Kepner * one of our devices needs to be removed - find it 337695ed63f7SArthur Kepner * and remove it 337795ed63f7SArthur Kepner */ 337895ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 337995ed63f7SArthur Kepner { 3380c26a8016SLuiz Capitulino struct list_head *q, *n; 3381c26a8016SLuiz Capitulino struct pktgen_dev *cur; 338295ed63f7SArthur Kepner 3383f9467eaeSJoe Perches func_enter(); 338495ed63f7SArthur Kepner 338595ed63f7SArthur Kepner if_lock(t); 338695ed63f7SArthur Kepner 3387c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3388c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 338995ed63f7SArthur Kepner 3390222f1806SLuiz Capitulino if (!cur->removal_mark) 3391222f1806SLuiz Capitulino continue; 339295ed63f7SArthur Kepner 339395ed63f7SArthur Kepner kfree_skb(cur->skb); 339495ed63f7SArthur Kepner cur->skb = NULL; 339595ed63f7SArthur Kepner 339695ed63f7SArthur Kepner pktgen_remove_device(t, cur); 339795ed63f7SArthur Kepner 339895ed63f7SArthur Kepner break; 339995ed63f7SArthur Kepner } 34001da177e4SLinus Torvalds 34011da177e4SLinus Torvalds if_unlock(t); 34021da177e4SLinus Torvalds } 34031da177e4SLinus Torvalds 34041da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 34051da177e4SLinus Torvalds { 3406c26a8016SLuiz Capitulino struct list_head *q, *n; 3407c26a8016SLuiz Capitulino struct pktgen_dev *cur; 34081da177e4SLinus Torvalds 3409f9467eaeSJoe Perches func_enter(); 3410f9467eaeSJoe Perches 34111da177e4SLinus Torvalds /* Remove all devices, free mem */ 34121da177e4SLinus Torvalds 34131da177e4SLinus Torvalds if_lock(t); 34141da177e4SLinus Torvalds 3415c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3416c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 341795ed63f7SArthur Kepner 341895ed63f7SArthur Kepner kfree_skb(cur->skb); 341995ed63f7SArthur Kepner cur->skb = NULL; 342095ed63f7SArthur Kepner 34211da177e4SLinus Torvalds pktgen_remove_device(t, cur); 34221da177e4SLinus Torvalds } 34231da177e4SLinus Torvalds 34241da177e4SLinus Torvalds if_unlock(t); 34251da177e4SLinus Torvalds } 34261da177e4SLinus Torvalds 34271da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 34281da177e4SLinus Torvalds { 34291da177e4SLinus Torvalds /* Remove from the thread list */ 34301da177e4SLinus Torvalds 3431ee74baa7SDavid S. Miller remove_proc_entry(t->tsk->comm, pg_proc_dir); 34321da177e4SLinus Torvalds 34336146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 34341da177e4SLinus Torvalds 3435cdcdbe0bSLuiz Capitulino list_del(&t->th_list); 3436cdcdbe0bSLuiz Capitulino 34376146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 34381da177e4SLinus Torvalds } 34391da177e4SLinus Torvalds 3440ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 34413791decbSStephen Hemminger { 3442fd29cf72SStephen Hemminger ktime_t idle_start = ktime_now(); 34433791decbSStephen Hemminger schedule(); 3444fd29cf72SStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 34453791decbSStephen Hemminger } 34463791decbSStephen Hemminger 3447ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3448ef87979cSStephen Hemminger { 3449ef87979cSStephen Hemminger ktime_t idle_start = ktime_now(); 3450ef87979cSStephen Hemminger 3451ef87979cSStephen Hemminger while (atomic_read(&(pkt_dev->skb->users)) != 1) { 3452ef87979cSStephen Hemminger if (signal_pending(current)) 3453ef87979cSStephen Hemminger break; 3454ef87979cSStephen Hemminger 3455ef87979cSStephen Hemminger if (need_resched()) 3456ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3457ef87979cSStephen Hemminger else 3458ef87979cSStephen Hemminger cpu_relax(); 3459ef87979cSStephen Hemminger } 3460ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 3461ef87979cSStephen Hemminger } 3462fd29cf72SStephen Hemminger 3463475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34641da177e4SLinus Torvalds { 346500829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 34666fef4c0cSStephen Hemminger netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *) 346700829823SStephen Hemminger = odev->netdev_ops->ndo_start_xmit; 3468fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 3469fd2ea0a7SDavid S. Miller u16 queue_map; 34701da177e4SLinus Torvalds int ret; 34711da177e4SLinus Torvalds 3472ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3473ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34741da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34753791decbSStephen Hemminger return; 34761da177e4SLinus Torvalds } 34771da177e4SLinus Torvalds 3478ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3479ef87979cSStephen Hemminger * "never transmit" 3480ef87979cSStephen Hemminger */ 3481ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3482ef87979cSStephen Hemminger pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); 3483ef87979cSStephen Hemminger return; 3484ef87979cSStephen Hemminger } 3485ef87979cSStephen Hemminger 3486ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 34877d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 34887d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 34891da177e4SLinus Torvalds /* build a new pkt */ 34901da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 34911da177e4SLinus Torvalds 34921da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 34931da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3494f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 34951da177e4SLinus Torvalds schedule(); 34961da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 34973791decbSStephen Hemminger return; 34981da177e4SLinus Torvalds } 3499baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 35001da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 35011da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 35021da177e4SLinus Torvalds } 35031da177e4SLinus Torvalds 3504ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3505ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3506ef87979cSStephen Hemminger 3507fd2ea0a7SDavid S. Miller queue_map = skb_get_queue_mapping(pkt_dev->skb); 3508fd2ea0a7SDavid S. Miller txq = netdev_get_tx_queue(odev, queue_map); 3509fd2ea0a7SDavid S. Miller 3510fd2ea0a7SDavid S. Miller __netif_tx_lock_bh(txq); 35115b8db2f5SStephen Hemminger 35120835acfeSEric Dumazet if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) { 3513ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 35140835acfeSEric Dumazet pkt_dev->last_ok = 0; 35150835acfeSEric Dumazet goto unlock; 35160835acfeSEric Dumazet } 35170835acfeSEric Dumazet atomic_inc(&(pkt_dev->skb->users)); 351800829823SStephen Hemminger ret = (*xmit)(pkt_dev->skb, odev); 3519ef87979cSStephen Hemminger 35205b8db2f5SStephen Hemminger switch (ret) { 35215b8db2f5SStephen Hemminger case NETDEV_TX_OK: 352208baf561SEric Dumazet txq_trans_update(txq); 35231da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35241da177e4SLinus Torvalds pkt_dev->sofar++; 35251da177e4SLinus Torvalds pkt_dev->seq_num++; 3526baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 35275b8db2f5SStephen Hemminger break; 3528f466dba1SJohn Fastabend case NET_XMIT_DROP: 3529f466dba1SJohn Fastabend case NET_XMIT_CN: 3530f466dba1SJohn Fastabend case NET_XMIT_POLICED: 3531f466dba1SJohn Fastabend /* skb has been consumed */ 3532f466dba1SJohn Fastabend pkt_dev->errors++; 3533f466dba1SJohn Fastabend break; 35345b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 35355b8db2f5SStephen Hemminger if (net_ratelimit()) 35365b8db2f5SStephen Hemminger pr_info("pktgen: %s xmit error: %d\n", 3537593f63b0SEric Dumazet pkt_dev->odevname, ret); 35381da177e4SLinus Torvalds pkt_dev->errors++; 35395b8db2f5SStephen Hemminger /* fallthru */ 3540ef87979cSStephen Hemminger case NETDEV_TX_LOCKED: 35415b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35425b8db2f5SStephen Hemminger /* Retry it next time */ 35435b8db2f5SStephen Hemminger atomic_dec(&(pkt_dev->skb->users)); 35441da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35451da177e4SLinus Torvalds } 35460835acfeSEric Dumazet unlock: 3547fd2ea0a7SDavid S. Miller __netif_tx_unlock_bh(txq); 35481da177e4SLinus Torvalds 35491da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35501da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3551ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35521da177e4SLinus Torvalds 35531da177e4SLinus Torvalds /* Done with this */ 35541da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35551da177e4SLinus Torvalds } 35561da177e4SLinus Torvalds } 35571da177e4SLinus Torvalds 35581da177e4SLinus Torvalds /* 35591da177e4SLinus Torvalds * Main loop of the thread goes here 35601da177e4SLinus Torvalds */ 35611da177e4SLinus Torvalds 3562ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 35631da177e4SLinus Torvalds { 35641da177e4SLinus Torvalds DEFINE_WAIT(wait); 3565ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 35661da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 35671da177e4SLinus Torvalds int cpu = t->cpu; 35681da177e4SLinus Torvalds 3569ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 35701da177e4SLinus Torvalds 35711da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3572d3ede327SDenis V. Lunev complete(&t->start_done); 35731da177e4SLinus Torvalds 3574f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 35751da177e4SLinus Torvalds 3576ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 35771da177e4SLinus Torvalds 357883144186SRafael J. Wysocki set_freezable(); 357983144186SRafael J. Wysocki 3580ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3581ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3582ee74baa7SDavid S. Miller 3583ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 3584ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3585ef87979cSStephen Hemminger t->control != 0, 3586ef87979cSStephen Hemminger HZ/10); 35871b3f720bSRafael J. Wysocki try_to_freeze(); 3588ef87979cSStephen Hemminger continue; 3589ee74baa7SDavid S. Miller } 35901da177e4SLinus Torvalds 35911da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 35921da177e4SLinus Torvalds 3593ef87979cSStephen Hemminger if (likely(pkt_dev)) { 35941da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 35951da177e4SLinus Torvalds 3596ef87979cSStephen Hemminger if (need_resched()) 3597ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3598ef87979cSStephen Hemminger else 3599ef87979cSStephen Hemminger cpu_relax(); 3600ef87979cSStephen Hemminger } 3601ef87979cSStephen Hemminger 36021da177e4SLinus Torvalds if (t->control & T_STOP) { 36031da177e4SLinus Torvalds pktgen_stop(t); 36041da177e4SLinus Torvalds t->control &= ~(T_STOP); 36051da177e4SLinus Torvalds } 36061da177e4SLinus Torvalds 36071da177e4SLinus Torvalds if (t->control & T_RUN) { 36081da177e4SLinus Torvalds pktgen_run(t); 36091da177e4SLinus Torvalds t->control &= ~(T_RUN); 36101da177e4SLinus Torvalds } 36111da177e4SLinus Torvalds 361295ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36131da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 361495ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 361595ed63f7SArthur Kepner } 361695ed63f7SArthur Kepner 361795ed63f7SArthur Kepner if (t->control & T_REMDEV) { 361895ed63f7SArthur Kepner pktgen_rem_one_if(t); 36191da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36201da177e4SLinus Torvalds } 36211da177e4SLinus Torvalds 362209fe3ef4SAndrew Morton try_to_freeze(); 362309fe3ef4SAndrew Morton 3624ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 36251da177e4SLinus Torvalds } 36261da177e4SLinus Torvalds 3627f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36281da177e4SLinus Torvalds pktgen_stop(t); 36291da177e4SLinus Torvalds 3630f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36311da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36321da177e4SLinus Torvalds 3633f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36341da177e4SLinus Torvalds pktgen_rem_thread(t); 3635cdcdbe0bSLuiz Capitulino 3636ee74baa7SDavid S. Miller return 0; 36371da177e4SLinus Torvalds } 36381da177e4SLinus Torvalds 3639222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36403e984840SEric Dumazet const char *ifname, bool exact) 36411da177e4SLinus Torvalds { 3642c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36433e984840SEric Dumazet size_t len = strlen(ifname); 36441da177e4SLinus Torvalds 36453e984840SEric Dumazet if_lock(t); 3646c26a8016SLuiz Capitulino list_for_each_entry(p, &t->if_list, list) 36473e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36483e984840SEric Dumazet if (p->odevname[len]) { 36493e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36503e984840SEric Dumazet continue; 36513e984840SEric Dumazet } 3652c26a8016SLuiz Capitulino pkt_dev = p; 36531da177e4SLinus Torvalds break; 36541da177e4SLinus Torvalds } 36551da177e4SLinus Torvalds 36561da177e4SLinus Torvalds if_unlock(t); 3657f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36581da177e4SLinus Torvalds return pkt_dev; 36591da177e4SLinus Torvalds } 36601da177e4SLinus Torvalds 36611da177e4SLinus Torvalds /* 36621da177e4SLinus Torvalds * Adds a dev at front of if_list. 36631da177e4SLinus Torvalds */ 36641da177e4SLinus Torvalds 3665222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3666222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36671da177e4SLinus Torvalds { 36681da177e4SLinus Torvalds int rv = 0; 36691da177e4SLinus Torvalds 36701da177e4SLinus Torvalds if_lock(t); 36711da177e4SLinus Torvalds 36721da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3673f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 36741da177e4SLinus Torvalds rv = -EBUSY; 36751da177e4SLinus Torvalds goto out; 36761da177e4SLinus Torvalds } 3677c26a8016SLuiz Capitulino 3678c26a8016SLuiz Capitulino list_add(&pkt_dev->list, &t->if_list); 36791da177e4SLinus Torvalds pkt_dev->pg_thread = t; 36801da177e4SLinus Torvalds pkt_dev->running = 0; 36811da177e4SLinus Torvalds 36821da177e4SLinus Torvalds out: 36831da177e4SLinus Torvalds if_unlock(t); 36841da177e4SLinus Torvalds return rv; 36851da177e4SLinus Torvalds } 36861da177e4SLinus Torvalds 36871da177e4SLinus Torvalds /* Called under thread lock */ 36881da177e4SLinus Torvalds 36891da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 36901da177e4SLinus Torvalds { 36911da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 369239df232fSStephen Hemminger int err; 36933291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 36941da177e4SLinus Torvalds 36951da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 36961da177e4SLinus Torvalds 3697d50a6b56SStephen Hemminger pkt_dev = __pktgen_NN_threads(ifname, FIND); 3698d50a6b56SStephen Hemminger if (pkt_dev) { 3699f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3700d50a6b56SStephen Hemminger return -EBUSY; 3701d50a6b56SStephen Hemminger } 37021da177e4SLinus Torvalds 37033291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37041da177e4SLinus Torvalds if (!pkt_dev) 37051da177e4SLinus Torvalds return -ENOMEM; 37061da177e4SLinus Torvalds 3707593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 37083291b9dbSEric Dumazet pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 37093291b9dbSEric Dumazet node); 37101da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37111da177e4SLinus Torvalds kfree(pkt_dev); 37121da177e4SLinus Torvalds return -ENOMEM; 37131da177e4SLinus Torvalds } 37141da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); 37151da177e4SLinus Torvalds 371695ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37171da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 37181da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 37191da177e4SLinus Torvalds pkt_dev->nfrags = 0; 37201da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 3721fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37221da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37231da177e4SLinus Torvalds pkt_dev->sofar = 0; 37241da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37251da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37261da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37271da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 37281da177e4SLinus Torvalds 372934954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 373034954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 373134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 373234954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 373334954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 373434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 3735e99b99b4SRobert Olsson pkt_dev->node = -1; 373634954ddcSFrancesco Fondelli 373739df232fSStephen Hemminger err = pktgen_setup_dev(pkt_dev, ifname); 373839df232fSStephen Hemminger if (err) 373939df232fSStephen Hemminger goto out1; 37401da177e4SLinus Torvalds 37415efdccbcSDenis V. Lunev pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir, 37425efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 374339df232fSStephen Hemminger if (!pkt_dev->entry) { 3744f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3745d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 374639df232fSStephen Hemminger err = -EINVAL; 374739df232fSStephen Hemminger goto out2; 374839df232fSStephen Hemminger } 3749a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3750a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3751a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3752a553e4a6SJamal Hadi Salim #endif 375339df232fSStephen Hemminger 375439df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 375539df232fSStephen Hemminger out2: 375639df232fSStephen Hemminger dev_put(pkt_dev->odev); 375739df232fSStephen Hemminger out1: 3758a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3759a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3760a553e4a6SJamal Hadi Salim #endif 37611da177e4SLinus Torvalds vfree(pkt_dev->flows); 37621da177e4SLinus Torvalds kfree(pkt_dev); 376339df232fSStephen Hemminger return err; 37641da177e4SLinus Torvalds } 37651da177e4SLinus Torvalds 3766ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu) 37671da177e4SLinus Torvalds { 3768cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3769d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3770ee74baa7SDavid S. Miller struct task_struct *p; 37711da177e4SLinus Torvalds 37723291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 37733291b9dbSEric Dumazet cpu_to_node(cpu)); 37741da177e4SLinus Torvalds if (!t) { 3775f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 37761da177e4SLinus Torvalds return -ENOMEM; 37771da177e4SLinus Torvalds } 37781da177e4SLinus Torvalds 37791da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 37801da177e4SLinus Torvalds t->cpu = cpu; 37811da177e4SLinus Torvalds 3782ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3783ee74baa7SDavid S. Miller 3784ee74baa7SDavid S. Miller list_add_tail(&t->th_list, &pktgen_threads); 3785d3ede327SDenis V. Lunev init_completion(&t->start_done); 3786ee74baa7SDavid S. Miller 3787ee74baa7SDavid S. Miller p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); 3788ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3789f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3790ee74baa7SDavid S. Miller list_del(&t->th_list); 3791ee74baa7SDavid S. Miller kfree(t); 3792ee74baa7SDavid S. Miller return PTR_ERR(p); 3793ee74baa7SDavid S. Miller } 3794ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3795ee74baa7SDavid S. Miller t->tsk = p; 3796ee74baa7SDavid S. Miller 37975efdccbcSDenis V. Lunev pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir, 37985efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3799d50a6b56SStephen Hemminger if (!pe) { 3800f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3801ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3802ee74baa7SDavid S. Miller kthread_stop(p); 3803ee74baa7SDavid S. Miller list_del(&t->th_list); 38041da177e4SLinus Torvalds kfree(t); 38051da177e4SLinus Torvalds return -EINVAL; 38061da177e4SLinus Torvalds } 3807d50a6b56SStephen Hemminger 3808ee74baa7SDavid S. Miller wake_up_process(p); 3809d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38101da177e4SLinus Torvalds 38111da177e4SLinus Torvalds return 0; 38121da177e4SLinus Torvalds } 38131da177e4SLinus Torvalds 38141da177e4SLinus Torvalds /* 38151da177e4SLinus Torvalds * Removes a device from the thread if_list. 38161da177e4SLinus Torvalds */ 3817222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3818222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38191da177e4SLinus Torvalds { 3820c26a8016SLuiz Capitulino struct list_head *q, *n; 3821c26a8016SLuiz Capitulino struct pktgen_dev *p; 38221da177e4SLinus Torvalds 3823c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3824c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3825c26a8016SLuiz Capitulino if (p == pkt_dev) 3826c26a8016SLuiz Capitulino list_del(&p->list); 38271da177e4SLinus Torvalds } 38281da177e4SLinus Torvalds } 38291da177e4SLinus Torvalds 3830222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3831222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38321da177e4SLinus Torvalds { 38331da177e4SLinus Torvalds 3834f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38351da177e4SLinus Torvalds 38361da177e4SLinus Torvalds if (pkt_dev->running) { 3837f9467eaeSJoe Perches pr_warning("WARNING: trying to remove a running interface, stopping it now\n"); 38381da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38391da177e4SLinus Torvalds } 38401da177e4SLinus Torvalds 38411da177e4SLinus Torvalds /* Dis-associate from the interface */ 38421da177e4SLinus Torvalds 38431da177e4SLinus Torvalds if (pkt_dev->odev) { 38441da177e4SLinus Torvalds dev_put(pkt_dev->odev); 38451da177e4SLinus Torvalds pkt_dev->odev = NULL; 38461da177e4SLinus Torvalds } 38471da177e4SLinus Torvalds 38481da177e4SLinus Torvalds /* And update the thread if_list */ 38491da177e4SLinus Torvalds 38501da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 38511da177e4SLinus Torvalds 385239df232fSStephen Hemminger if (pkt_dev->entry) 385339df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 38541da177e4SLinus Torvalds 3855a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3856a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3857a553e4a6SJamal Hadi Salim #endif 38581da177e4SLinus Torvalds vfree(pkt_dev->flows); 38591da177e4SLinus Torvalds kfree(pkt_dev); 38601da177e4SLinus Torvalds return 0; 38611da177e4SLinus Torvalds } 38621da177e4SLinus Torvalds 38631da177e4SLinus Torvalds static int __init pg_init(void) 38641da177e4SLinus Torvalds { 38651da177e4SLinus Torvalds int cpu; 3866d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3867d50a6b56SStephen Hemminger 3868f9467eaeSJoe Perches pr_info("%s", version); 38691da177e4SLinus Torvalds 3870457c4cbcSEric W. Biederman pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); 3871d50a6b56SStephen Hemminger if (!pg_proc_dir) 3872d50a6b56SStephen Hemminger return -ENODEV; 38731da177e4SLinus Torvalds 387425296d59SWang Chen pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); 3875d50a6b56SStephen Hemminger if (pe == NULL) { 3876f9467eaeSJoe Perches pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); 3877457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 38781da177e4SLinus Torvalds return -EINVAL; 38791da177e4SLinus Torvalds } 38801da177e4SLinus Torvalds 38811da177e4SLinus Torvalds /* Register us to receive netdevice events */ 38821da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 38831da177e4SLinus Torvalds 3884670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 38858024bb24SLuiz Capitulino int err; 38861da177e4SLinus Torvalds 3887ee74baa7SDavid S. Miller err = pktgen_create_thread(cpu); 38888024bb24SLuiz Capitulino if (err) 3889f9467eaeSJoe Perches pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n", 3890f9467eaeSJoe Perches cpu, err); 38911da177e4SLinus Torvalds } 38928024bb24SLuiz Capitulino 38938024bb24SLuiz Capitulino if (list_empty(&pktgen_threads)) { 3894f9467eaeSJoe Perches pr_err("ERROR: Initialization failed for all threads\n"); 38958024bb24SLuiz Capitulino unregister_netdevice_notifier(&pktgen_notifier_block); 38968024bb24SLuiz Capitulino remove_proc_entry(PGCTRL, pg_proc_dir); 3897457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 38988024bb24SLuiz Capitulino return -ENODEV; 38998024bb24SLuiz Capitulino } 39008024bb24SLuiz Capitulino 39011da177e4SLinus Torvalds return 0; 39021da177e4SLinus Torvalds } 39031da177e4SLinus Torvalds 39041da177e4SLinus Torvalds static void __exit pg_cleanup(void) 39051da177e4SLinus Torvalds { 3906cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3907cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 39081da177e4SLinus Torvalds 39091da177e4SLinus Torvalds /* Stop all interfaces & threads */ 39101da177e4SLinus Torvalds 3911cdcdbe0bSLuiz Capitulino list_for_each_safe(q, n, &pktgen_threads) { 3912cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3913ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3914ee74baa7SDavid S. Miller kfree(t); 39151da177e4SLinus Torvalds } 39161da177e4SLinus Torvalds 39171da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 39181da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 39191da177e4SLinus Torvalds 39201da177e4SLinus Torvalds /* Clean up proc file system */ 3921d50a6b56SStephen Hemminger remove_proc_entry(PGCTRL, pg_proc_dir); 3922457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39231da177e4SLinus Torvalds } 39241da177e4SLinus Torvalds 39251da177e4SLinus Torvalds module_init(pg_init); 39261da177e4SLinus Torvalds module_exit(pg_cleanup); 39271da177e4SLinus Torvalds 3928c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 39291da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 39301da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3931c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 39321da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3933c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 39341da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3935c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 39361da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3937c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 39381da177e4SLinus Torvalds module_param(debug, int, 0); 3939c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3940