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++) { 73282fd5b5dSAndy Shevchenko int value; 733ca6549afSSteven Whitehouse char c; 734ca6549afSSteven Whitehouse *num <<= 4; 735ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 736ca6549afSSteven Whitehouse return -EFAULT; 73782fd5b5dSAndy Shevchenko value = hex_to_bin(c); 73882fd5b5dSAndy Shevchenko if (value >= 0) 73982fd5b5dSAndy 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 { 774d6182223SPaul Gortmaker int i; 7751da177e4SLinus Torvalds *num = 0; 7761da177e4SLinus Torvalds 777d6182223SPaul Gortmaker for (i = 0; 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 { 792d6182223SPaul Gortmaker int i; 7931da177e4SLinus Torvalds 794d6182223SPaul Gortmaker for (i = 0; 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; 849d6182223SPaul Gortmaker int i, 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 863d6182223SPaul Gortmaker max = count; 864d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8651da177e4SLinus Torvalds if (tmp < 0) { 866f9467eaeSJoe Perches pr_warning("illegal format\n"); 8671da177e4SLinus Torvalds return tmp; 8681da177e4SLinus Torvalds } 869d6182223SPaul Gortmaker 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) { 890*448d7b5dSNelson Elhage size_t copy = min(count, 1023); 891*448d7b5dSNelson Elhage char tb[copy + 1]; 892*448d7b5dSNelson Elhage if (copy_from_user(tb, user_buffer, copy)) 8931da177e4SLinus Torvalds return -EFAULT; 894*448d7b5dSNelson Elhage tb[copy] = 0; 89525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, 896d50a6b56SStephen Hemminger (unsigned long)count, tb); 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9001da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 90163adc6fbSStephen Hemminger if (len < 0) 902222f1806SLuiz Capitulino return len; 90363adc6fbSStephen Hemminger 9041da177e4SLinus Torvalds i += len; 9051da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9061da177e4SLinus Torvalds value = 14 + 20 + 8; 9071da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9081da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9091da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9101da177e4SLinus Torvalds } 911222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 912222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9131da177e4SLinus Torvalds return count; 9141da177e4SLinus Torvalds } 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9171da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 91863adc6fbSStephen Hemminger if (len < 0) 919222f1806SLuiz Capitulino return len; 92063adc6fbSStephen Hemminger 9211da177e4SLinus Torvalds i += len; 9221da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9231da177e4SLinus Torvalds value = 14 + 20 + 8; 9241da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9251da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9261da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9271da177e4SLinus Torvalds } 928222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 929222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9301da177e4SLinus Torvalds return count; 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds /* Shortcut for min = max */ 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9361da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 93763adc6fbSStephen Hemminger if (len < 0) 938222f1806SLuiz Capitulino return len; 93963adc6fbSStephen Hemminger 9401da177e4SLinus Torvalds i += len; 9411da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9421da177e4SLinus Torvalds value = 14 + 20 + 8; 9431da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9441da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9451da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9461da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9491da177e4SLinus Torvalds return count; 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9531da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 95463adc6fbSStephen Hemminger if (len < 0) 955222f1806SLuiz Capitulino return len; 95663adc6fbSStephen Hemminger 9571da177e4SLinus Torvalds i += len; 9581da177e4SLinus Torvalds debug = value; 9591da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9601da177e4SLinus Torvalds return count; 9611da177e4SLinus Torvalds } 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9641da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 96563adc6fbSStephen Hemminger if (len < 0) 966222f1806SLuiz Capitulino return len; 96763adc6fbSStephen Hemminger 9681da177e4SLinus Torvalds i += len; 9691da177e4SLinus Torvalds pkt_dev->nfrags = value; 9701da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 9711da177e4SLinus Torvalds return count; 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9741da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97563adc6fbSStephen Hemminger if (len < 0) 976222f1806SLuiz Capitulino return len; 97763adc6fbSStephen Hemminger 9781da177e4SLinus Torvalds i += len; 979fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 980fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 981fd29cf72SStephen Hemminger else 9829240d715SEric Dumazet pkt_dev->delay = (u64)value; 983fd29cf72SStephen Hemminger 984fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 985fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9861da177e4SLinus Torvalds return count; 9871da177e4SLinus Torvalds } 98843d28b65SDaniel Turull if (!strcmp(name, "rate")) { 98943d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 99043d28b65SDaniel Turull if (len < 0) 99143d28b65SDaniel Turull return len; 99243d28b65SDaniel Turull 99343d28b65SDaniel Turull i += len; 99443d28b65SDaniel Turull if (!value) 99543d28b65SDaniel Turull return len; 99643d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 99743d28b65SDaniel Turull if (debug) 998f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 99943d28b65SDaniel Turull 100043d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 100143d28b65SDaniel Turull return count; 100243d28b65SDaniel Turull } 100343d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 100443d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 100543d28b65SDaniel Turull if (len < 0) 100643d28b65SDaniel Turull return len; 100743d28b65SDaniel Turull 100843d28b65SDaniel Turull i += len; 100943d28b65SDaniel Turull if (!value) 101043d28b65SDaniel Turull return len; 101143d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 101243d28b65SDaniel Turull if (debug) 1013f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 101443d28b65SDaniel Turull 101543d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 101643d28b65SDaniel Turull return count; 101743d28b65SDaniel Turull } 10181da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10191da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 102063adc6fbSStephen Hemminger if (len < 0) 1021222f1806SLuiz Capitulino return len; 102263adc6fbSStephen Hemminger 10231da177e4SLinus Torvalds i += len; 10241da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10251da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10261da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10291da177e4SLinus Torvalds return count; 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10321da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 103363adc6fbSStephen Hemminger if (len < 0) 1034222f1806SLuiz Capitulino return len; 103563adc6fbSStephen Hemminger 10361da177e4SLinus Torvalds i += len; 10371da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10381da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10391da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10421da177e4SLinus Torvalds return count; 10431da177e4SLinus Torvalds } 10441da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10451da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104663adc6fbSStephen Hemminger if (len < 0) 1047222f1806SLuiz Capitulino return len; 104863adc6fbSStephen Hemminger 10491da177e4SLinus Torvalds i += len; 10501da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10511da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10521da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10531da177e4SLinus Torvalds } 10541da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10551da177e4SLinus Torvalds return count; 10561da177e4SLinus Torvalds } 10571da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10581da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105963adc6fbSStephen Hemminger if (len < 0) 1060222f1806SLuiz Capitulino return len; 106163adc6fbSStephen Hemminger 10621da177e4SLinus Torvalds i += len; 10631da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10641da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10651da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10661da177e4SLinus Torvalds } 10671da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10681da177e4SLinus Torvalds return count; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10711da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107263adc6fbSStephen Hemminger if (len < 0) 1073222f1806SLuiz Capitulino return len; 107463adc6fbSStephen Hemminger 10751da177e4SLinus Torvalds i += len; 10761da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10791da177e4SLinus Torvalds return count; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10821da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108363adc6fbSStephen Hemminger if (len < 0) 1084222f1806SLuiz Capitulino return len; 108563adc6fbSStephen Hemminger 10861da177e4SLinus Torvalds i += len; 10871da177e4SLinus Torvalds pkt_dev->count = value; 10881da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 10891da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 10901da177e4SLinus Torvalds return count; 10911da177e4SLinus Torvalds } 10921da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 10931da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109463adc6fbSStephen Hemminger if (len < 0) 1095222f1806SLuiz Capitulino return len; 109663adc6fbSStephen Hemminger 10971da177e4SLinus Torvalds i += len; 10981da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 10991da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11001da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11011da177e4SLinus Torvalds } 1102222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1103222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11041da177e4SLinus Torvalds return count; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11071da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110863adc6fbSStephen Hemminger if (len < 0) 1109222f1806SLuiz Capitulino return len; 111063adc6fbSStephen Hemminger 11111da177e4SLinus Torvalds i += len; 11121da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11131da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11141da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11151da177e4SLinus Torvalds } 1116222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1117222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11181da177e4SLinus Torvalds return count; 11191da177e4SLinus Torvalds } 1120e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1121e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1122e99b99b4SRobert Olsson if (len < 0) 1123e99b99b4SRobert Olsson return len; 1124e99b99b4SRobert Olsson 1125e99b99b4SRobert Olsson i += len; 1126e99b99b4SRobert Olsson 1127e99b99b4SRobert Olsson if (node_possible(value)) { 1128e99b99b4SRobert Olsson pkt_dev->node = value; 1129e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 1130e99b99b4SRobert Olsson } 1131e99b99b4SRobert Olsson else 1132e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1133e99b99b4SRobert Olsson return count; 1134e99b99b4SRobert Olsson } 11351da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11361da177e4SLinus Torvalds char f[32]; 11371da177e4SLinus Torvalds memset(f, 0, 32); 11381da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 113963adc6fbSStephen Hemminger if (len < 0) 1140222f1806SLuiz Capitulino return len; 114163adc6fbSStephen Hemminger 11421da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11431da177e4SLinus Torvalds return -EFAULT; 11441da177e4SLinus Torvalds i += len; 11451da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11461da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11491da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11501da177e4SLinus Torvalds 11511da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11521da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11551da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11581da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11591da177e4SLinus Torvalds 11601da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11611da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11641da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11671da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11701da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11731da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11761da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11791da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11821da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11851da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11861da177e4SLinus Torvalds 1187ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1188ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1189ca6549afSSteven Whitehouse 1190ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1191ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1192ca6549afSSteven Whitehouse 119334954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 119434954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 119534954ddcSFrancesco Fondelli 119634954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 119734954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 119834954ddcSFrancesco Fondelli 119934954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 120034954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 120134954ddcSFrancesco Fondelli 120234954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 120334954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 120434954ddcSFrancesco Fondelli 1205007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1206007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1207007a531bSJamal Hadi Salim 120845b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 120945b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 121045b270f8SRobert Olsson 121145b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 121245b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1213e6fce5b9SRobert Olsson 1214e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1215e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1216e6fce5b9SRobert Olsson 1217e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1218e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1219a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1220a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1221a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1222a553e4a6SJamal Hadi Salim #endif 1223a553e4a6SJamal Hadi Salim 12241ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12251ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12261ca7768cSFrancesco Fondelli 1227e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1228e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1229e99b99b4SRobert Olsson 1230e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1231e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1232e99b99b4SRobert Olsson 12331da177e4SLinus Torvalds else { 1234222f1806SLuiz Capitulino sprintf(pg_result, 1235222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12361da177e4SLinus Torvalds f, 12371ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 1238e99b99b4SRobert Olsson "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n"); 12391da177e4SLinus Torvalds return count; 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12421da177e4SLinus Torvalds return count; 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12451da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 124663adc6fbSStephen Hemminger if (len < 0) 1247222f1806SLuiz Capitulino return len; 12481da177e4SLinus Torvalds 12491da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12501da177e4SLinus Torvalds return -EFAULT; 12511da177e4SLinus Torvalds buf[len] = 0; 12521da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12531da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12541da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12551da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12561da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12571da177e4SLinus Torvalds } 12581da177e4SLinus Torvalds if (debug) 125925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_min set to: %s\n", 1260222f1806SLuiz Capitulino pkt_dev->dst_min); 12611da177e4SLinus Torvalds i += len; 12621da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12631da177e4SLinus Torvalds return count; 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12661da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 126763adc6fbSStephen Hemminger if (len < 0) 1268222f1806SLuiz Capitulino return len; 126963adc6fbSStephen Hemminger 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12721da177e4SLinus Torvalds return -EFAULT; 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds buf[len] = 0; 12751da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12761da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12771da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 12781da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12791da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds if (debug) 128225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_max set to: %s\n", 1283222f1806SLuiz Capitulino pkt_dev->dst_max); 12841da177e4SLinus Torvalds i += len; 12851da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12861da177e4SLinus Torvalds return count; 12871da177e4SLinus Torvalds } 12881da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12891da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1290222f1806SLuiz Capitulino if (len < 0) 1291222f1806SLuiz Capitulino return len; 12921da177e4SLinus Torvalds 12931da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 12941da177e4SLinus Torvalds 12951da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12961da177e4SLinus Torvalds return -EFAULT; 12971da177e4SLinus Torvalds buf[len] = 0; 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13001da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13011da177e4SLinus Torvalds 13021da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds if (debug) 130525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf); 13061da177e4SLinus Torvalds 13071da177e4SLinus Torvalds i += len; 13081da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13091da177e4SLinus Torvalds return count; 13101da177e4SLinus Torvalds } 13111da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13121da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1313222f1806SLuiz Capitulino if (len < 0) 1314222f1806SLuiz Capitulino return len; 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13191da177e4SLinus Torvalds return -EFAULT; 13201da177e4SLinus Torvalds buf[len] = 0; 13211da177e4SLinus Torvalds 13221da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13231da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13241da177e4SLinus Torvalds 1325222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev->cur_in6_daddr, 1326222f1806SLuiz Capitulino &pkt_dev->min_in6_daddr); 13271da177e4SLinus Torvalds if (debug) 132825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf); 13291da177e4SLinus Torvalds 13301da177e4SLinus Torvalds i += len; 13311da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13321da177e4SLinus Torvalds return count; 13331da177e4SLinus Torvalds } 13341da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13351da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1336222f1806SLuiz Capitulino if (len < 0) 1337222f1806SLuiz Capitulino return len; 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13421da177e4SLinus Torvalds return -EFAULT; 13431da177e4SLinus Torvalds buf[len] = 0; 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13461da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds if (debug) 134925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds i += len; 13521da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13531da177e4SLinus Torvalds return count; 13541da177e4SLinus Torvalds } 13551da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13561da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1357222f1806SLuiz Capitulino if (len < 0) 1358222f1806SLuiz Capitulino return len; 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13631da177e4SLinus Torvalds return -EFAULT; 13641da177e4SLinus Torvalds buf[len] = 0; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13671da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds if (debug) 137225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf); 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds i += len; 13751da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13761da177e4SLinus Torvalds return count; 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13791da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 138063adc6fbSStephen Hemminger if (len < 0) 1381222f1806SLuiz Capitulino return len; 138263adc6fbSStephen Hemminger 13831da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13841da177e4SLinus Torvalds return -EFAULT; 13851da177e4SLinus Torvalds buf[len] = 0; 13861da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13871da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13881da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 13891da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13901da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13911da177e4SLinus Torvalds } 13921da177e4SLinus Torvalds if (debug) 139325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_min set to: %s\n", 1394222f1806SLuiz Capitulino pkt_dev->src_min); 13951da177e4SLinus Torvalds i += len; 13961da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 13971da177e4SLinus Torvalds return count; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 14001da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 140163adc6fbSStephen Hemminger if (len < 0) 1402222f1806SLuiz Capitulino return len; 140363adc6fbSStephen Hemminger 14041da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14051da177e4SLinus Torvalds return -EFAULT; 14061da177e4SLinus Torvalds buf[len] = 0; 14071da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14081da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14091da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14101da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14111da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14121da177e4SLinus Torvalds } 14131da177e4SLinus Torvalds if (debug) 141425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_max set to: %s\n", 1415222f1806SLuiz Capitulino pkt_dev->src_max); 14161da177e4SLinus Torvalds i += len; 14171da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14181da177e4SLinus Torvalds return count; 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14211da177e4SLinus Torvalds char *v = valstr; 1422f404e9a6SKris Katterjohn unsigned char old_dmac[ETH_ALEN]; 14231da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1424f404e9a6SKris Katterjohn memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 142763adc6fbSStephen Hemminger if (len < 0) 1428222f1806SLuiz Capitulino return len; 142963adc6fbSStephen Hemminger 14301da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14311da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14321da177e4SLinus Torvalds return -EFAULT; 14331da177e4SLinus Torvalds i += len; 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { 1436451e07a2SAndy Shevchenko int value; 1437451e07a2SAndy Shevchenko 1438451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1439451e07a2SAndy Shevchenko if (value >= 0) 1440451e07a2SAndy Shevchenko *m = *m * 16 + value; 1441451e07a2SAndy Shevchenko 14421da177e4SLinus Torvalds if (*v == ':') { 14431da177e4SLinus Torvalds m++; 14441da177e4SLinus Torvalds *m = 0; 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds /* Set up Dest MAC */ 1449f404e9a6SKris Katterjohn if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) 1450f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 14531da177e4SLinus Torvalds return count; 14541da177e4SLinus Torvalds } 14551da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14561da177e4SLinus Torvalds char *v = valstr; 1457ce5d0b47SAdit Ranadive unsigned char old_smac[ETH_ALEN]; 14581da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 14591da177e4SLinus Torvalds 1460ce5d0b47SAdit Ranadive memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); 1461ce5d0b47SAdit Ranadive 14621da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 146363adc6fbSStephen Hemminger if (len < 0) 1464222f1806SLuiz Capitulino return len; 146563adc6fbSStephen Hemminger 14661da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14671da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14681da177e4SLinus Torvalds return -EFAULT; 14691da177e4SLinus Torvalds i += len; 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { 1472451e07a2SAndy Shevchenko int value; 1473451e07a2SAndy Shevchenko 1474451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1475451e07a2SAndy Shevchenko if (value >= 0) 1476451e07a2SAndy Shevchenko *m = *m * 16 + value; 1477451e07a2SAndy Shevchenko 14781da177e4SLinus Torvalds if (*v == ':') { 14791da177e4SLinus Torvalds m++; 14801da177e4SLinus Torvalds *m = 0; 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 1484ce5d0b47SAdit Ranadive /* Set up Src MAC */ 1485ce5d0b47SAdit Ranadive if (compare_ether_addr(old_smac, pkt_dev->src_mac)) 1486ce5d0b47SAdit Ranadive memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); 1487ce5d0b47SAdit Ranadive 14881da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 14891da177e4SLinus Torvalds return count; 14901da177e4SLinus Torvalds } 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14931da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 14941da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 14951da177e4SLinus Torvalds return count; 14961da177e4SLinus Torvalds } 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 14991da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 150063adc6fbSStephen Hemminger if (len < 0) 1501222f1806SLuiz Capitulino return len; 150263adc6fbSStephen Hemminger 15031da177e4SLinus Torvalds i += len; 15041da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15051da177e4SLinus Torvalds value = MAX_CFLOWS; 15061da177e4SLinus Torvalds 15071da177e4SLinus Torvalds pkt_dev->cflows = value; 15081da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15091da177e4SLinus Torvalds return count; 15101da177e4SLinus Torvalds } 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15131da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 151463adc6fbSStephen Hemminger if (len < 0) 1515222f1806SLuiz Capitulino return len; 151663adc6fbSStephen Hemminger 15171da177e4SLinus Torvalds i += len; 15181da177e4SLinus Torvalds pkt_dev->lflow = value; 15191da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15201da177e4SLinus Torvalds return count; 15211da177e4SLinus Torvalds } 15221da177e4SLinus Torvalds 152345b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 152445b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 152563adc6fbSStephen Hemminger if (len < 0) 152645b270f8SRobert Olsson return len; 152763adc6fbSStephen Hemminger 152845b270f8SRobert Olsson i += len; 152945b270f8SRobert Olsson pkt_dev->queue_map_min = value; 153045b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 153145b270f8SRobert Olsson return count; 153245b270f8SRobert Olsson } 153345b270f8SRobert Olsson 153445b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 153545b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 153663adc6fbSStephen Hemminger if (len < 0) 153745b270f8SRobert Olsson return len; 153863adc6fbSStephen Hemminger 153945b270f8SRobert Olsson i += len; 154045b270f8SRobert Olsson pkt_dev->queue_map_max = value; 154145b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 154245b270f8SRobert Olsson return count; 154345b270f8SRobert Olsson } 154445b270f8SRobert Olsson 1545ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 1546cfcabdccSStephen Hemminger unsigned n, cnt; 1547cfcabdccSStephen Hemminger 1548ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1549cfcabdccSStephen Hemminger if (len < 0) 1550cfcabdccSStephen Hemminger return len; 1551ca6549afSSteven Whitehouse i += len; 1552cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1553ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1554cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1555ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1556ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 155734954ddcSFrancesco Fondelli 155834954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 155934954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 156034954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 156134954ddcSFrancesco Fondelli 156234954ddcSFrancesco Fondelli if (debug) 156325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); 156434954ddcSFrancesco Fondelli } 156534954ddcSFrancesco Fondelli return count; 156634954ddcSFrancesco Fondelli } 156734954ddcSFrancesco Fondelli 156834954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 156934954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 157063adc6fbSStephen Hemminger if (len < 0) 157134954ddcSFrancesco Fondelli return len; 157263adc6fbSStephen Hemminger 157334954ddcSFrancesco Fondelli i += len; 157434954ddcSFrancesco Fondelli if (value <= 4095) { 157534954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 157634954ddcSFrancesco Fondelli 157734954ddcSFrancesco Fondelli if (debug) 157825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN turned on\n"); 157934954ddcSFrancesco Fondelli 158034954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 158125a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 158234954ddcSFrancesco Fondelli 158334954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 158434954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 158534954ddcSFrancesco Fondelli } else { 158634954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 158734954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 158834954ddcSFrancesco Fondelli 158934954ddcSFrancesco Fondelli if (debug) 159025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 159134954ddcSFrancesco Fondelli } 159234954ddcSFrancesco Fondelli return count; 159334954ddcSFrancesco Fondelli } 159434954ddcSFrancesco Fondelli 159534954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 159634954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 159763adc6fbSStephen Hemminger if (len < 0) 159834954ddcSFrancesco Fondelli return len; 159963adc6fbSStephen Hemminger 160034954ddcSFrancesco Fondelli i += len; 160134954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 160234954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 160334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 160434954ddcSFrancesco Fondelli } else { 160534954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 160634954ddcSFrancesco Fondelli } 160734954ddcSFrancesco Fondelli return count; 160834954ddcSFrancesco Fondelli } 160934954ddcSFrancesco Fondelli 161034954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 161134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 161263adc6fbSStephen Hemminger if (len < 0) 161334954ddcSFrancesco Fondelli return len; 161463adc6fbSStephen Hemminger 161534954ddcSFrancesco Fondelli i += len; 161634954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 161734954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 161834954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 161934954ddcSFrancesco Fondelli } else { 162034954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 162134954ddcSFrancesco Fondelli } 162234954ddcSFrancesco Fondelli return count; 162334954ddcSFrancesco Fondelli } 162434954ddcSFrancesco Fondelli 162534954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 162634954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 162763adc6fbSStephen Hemminger if (len < 0) 162834954ddcSFrancesco Fondelli return len; 162963adc6fbSStephen Hemminger 163034954ddcSFrancesco Fondelli i += len; 163134954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 163234954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 163334954ddcSFrancesco Fondelli 163434954ddcSFrancesco Fondelli if (debug) 163525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); 163634954ddcSFrancesco Fondelli 163734954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 163825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 163934954ddcSFrancesco Fondelli 164034954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 164134954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 164234954ddcSFrancesco Fondelli } else { 164334954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 164534954ddcSFrancesco Fondelli 164634954ddcSFrancesco Fondelli if (debug) 164725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 164834954ddcSFrancesco Fondelli } 164934954ddcSFrancesco Fondelli return count; 165034954ddcSFrancesco Fondelli } 165134954ddcSFrancesco Fondelli 165234954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 165334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 165463adc6fbSStephen Hemminger if (len < 0) 165534954ddcSFrancesco Fondelli return len; 165663adc6fbSStephen Hemminger 165734954ddcSFrancesco Fondelli i += len; 165834954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 165934954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 166034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 166134954ddcSFrancesco Fondelli } else { 166234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 166334954ddcSFrancesco Fondelli } 166434954ddcSFrancesco Fondelli return count; 166534954ddcSFrancesco Fondelli } 166634954ddcSFrancesco Fondelli 166734954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 166834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 166963adc6fbSStephen Hemminger if (len < 0) 167034954ddcSFrancesco Fondelli return len; 167163adc6fbSStephen Hemminger 167234954ddcSFrancesco Fondelli i += len; 167334954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 167434954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 167534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 167634954ddcSFrancesco Fondelli } else { 167734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 167834954ddcSFrancesco Fondelli } 1679ca6549afSSteven Whitehouse return count; 1680ca6549afSSteven Whitehouse } 1681ca6549afSSteven Whitehouse 16821ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16831ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16841ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 168563adc6fbSStephen Hemminger if (len < 0) 16861ca7768cSFrancesco Fondelli return len; 168763adc6fbSStephen Hemminger 16881ca7768cSFrancesco Fondelli i += len; 16891ca7768cSFrancesco Fondelli if (len == 2) { 16901ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16911ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16921ca7768cSFrancesco Fondelli } else { 16931ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16941ca7768cSFrancesco Fondelli } 16951ca7768cSFrancesco Fondelli return count; 16961ca7768cSFrancesco Fondelli } 16971ca7768cSFrancesco Fondelli 16981ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 16991ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17001ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 170163adc6fbSStephen Hemminger if (len < 0) 17021ca7768cSFrancesco Fondelli return len; 170363adc6fbSStephen Hemminger 17041ca7768cSFrancesco Fondelli i += len; 17051ca7768cSFrancesco Fondelli if (len == 2) { 17061ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17071ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17081ca7768cSFrancesco Fondelli } else { 17091ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17101ca7768cSFrancesco Fondelli } 17111ca7768cSFrancesco Fondelli return count; 17121ca7768cSFrancesco Fondelli } 17131ca7768cSFrancesco Fondelli 17141da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17151da177e4SLinus Torvalds return -EINVAL; 17161da177e4SLinus Torvalds } 17171da177e4SLinus Torvalds 1718d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17191da177e4SLinus Torvalds { 1720d50a6b56SStephen Hemminger return single_open(file, pktgen_if_show, PDE(inode)->data); 17211da177e4SLinus Torvalds } 17221da177e4SLinus Torvalds 17239a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1724d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1725d50a6b56SStephen Hemminger .open = pktgen_if_open, 1726d50a6b56SStephen Hemminger .read = seq_read, 1727d50a6b56SStephen Hemminger .llseek = seq_lseek, 1728d50a6b56SStephen Hemminger .write = pktgen_if_write, 1729d50a6b56SStephen Hemminger .release = single_release, 1730d50a6b56SStephen Hemminger }; 1731d50a6b56SStephen Hemminger 1732d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1733d50a6b56SStephen Hemminger { 1734d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1735648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1736d50a6b56SStephen Hemminger 1737d50a6b56SStephen Hemminger BUG_ON(!t); 1738d50a6b56SStephen Hemminger 1739d50a6b56SStephen Hemminger seq_printf(seq, "Running: "); 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds if_lock(t); 1742c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17431da177e4SLinus Torvalds if (pkt_dev->running) 1744593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17451da177e4SLinus Torvalds 1746d50a6b56SStephen Hemminger seq_printf(seq, "\nStopped: "); 17471da177e4SLinus Torvalds 1748c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17491da177e4SLinus Torvalds if (!pkt_dev->running) 1750593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17511da177e4SLinus Torvalds 17521da177e4SLinus Torvalds if (t->result[0]) 1753d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17541da177e4SLinus Torvalds else 1755d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: NA\n"); 17561da177e4SLinus Torvalds 17571da177e4SLinus Torvalds if_unlock(t); 17581da177e4SLinus Torvalds 1759d50a6b56SStephen Hemminger return 0; 17601da177e4SLinus Torvalds } 17611da177e4SLinus Torvalds 1762d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1763d50a6b56SStephen Hemminger const char __user * user_buffer, 1764d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17651da177e4SLinus Torvalds { 17668a994a71SJoe Perches struct seq_file *seq = file->private_data; 1767d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1768d6182223SPaul Gortmaker int i, max, len, ret; 17691da177e4SLinus Torvalds char name[40]; 17701da177e4SLinus Torvalds char *pg_result; 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds if (count < 1) { 17731da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17741da177e4SLinus Torvalds return -EINVAL; 17751da177e4SLinus Torvalds } 17761da177e4SLinus Torvalds 1777d6182223SPaul Gortmaker max = count; 1778d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 17791da177e4SLinus Torvalds if (len < 0) 17801da177e4SLinus Torvalds return len; 17811da177e4SLinus Torvalds 1782d6182223SPaul Gortmaker i = len; 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds /* Read variable name */ 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 17871da177e4SLinus Torvalds if (len < 0) 17881da177e4SLinus Torvalds return len; 17891da177e4SLinus Torvalds 17901da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 17911da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 17921da177e4SLinus Torvalds return -EFAULT; 17931da177e4SLinus Torvalds i += len; 17941da177e4SLinus Torvalds 17951da177e4SLinus Torvalds max = count - i; 17961da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 17971da177e4SLinus Torvalds if (len < 0) 17981da177e4SLinus Torvalds return len; 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds i += len; 18011da177e4SLinus Torvalds 18021da177e4SLinus Torvalds if (debug) 180325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", 180425a8b254SDavid S. Miller name, (unsigned long)count); 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds if (!t) { 1807f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 18081da177e4SLinus Torvalds ret = -EINVAL; 18091da177e4SLinus Torvalds goto out; 18101da177e4SLinus Torvalds } 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds pg_result = &(t->result[0]); 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18151da177e4SLinus Torvalds char f[32]; 18161da177e4SLinus Torvalds memset(f, 0, 32); 18171da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18181da177e4SLinus Torvalds if (len < 0) { 18191da177e4SLinus Torvalds ret = len; 18201da177e4SLinus Torvalds goto out; 18211da177e4SLinus Torvalds } 18221da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18231da177e4SLinus Torvalds return -EFAULT; 18241da177e4SLinus Torvalds i += len; 18256146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18261da177e4SLinus Torvalds pktgen_add_device(t, f); 18276146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18281da177e4SLinus Torvalds ret = count; 18291da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 18301da177e4SLinus Torvalds goto out; 18311da177e4SLinus Torvalds } 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18346146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 183595ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18366146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1837121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18381da177e4SLinus Torvalds ret = count; 18391da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18401da177e4SLinus Torvalds goto out; 18411da177e4SLinus Torvalds } 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1844b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18451da177e4SLinus Torvalds ret = count; 18461da177e4SLinus Torvalds goto out; 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds ret = -EINVAL; 18501da177e4SLinus Torvalds out: 18511da177e4SLinus Torvalds return ret; 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds 1854d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18551da177e4SLinus Torvalds { 1856d50a6b56SStephen Hemminger return single_open(file, pktgen_thread_show, PDE(inode)->data); 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds 18599a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1860d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1861d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1862d50a6b56SStephen Hemminger .read = seq_read, 1863d50a6b56SStephen Hemminger .llseek = seq_lseek, 1864d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1865d50a6b56SStephen Hemminger .release = single_release, 1866d50a6b56SStephen Hemminger }; 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds /* Think find or remove for NN */ 18691da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) 18701da177e4SLinus Torvalds { 18711da177e4SLinus Torvalds struct pktgen_thread *t; 18721da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18733e984840SEric Dumazet bool exact = (remove == FIND); 18741da177e4SLinus Torvalds 1875cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 18763e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18771da177e4SLinus Torvalds if (pkt_dev) { 18781da177e4SLinus Torvalds if (remove) { 18791da177e4SLinus Torvalds if_lock(t); 188095ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 188195ed63f7SArthur Kepner t->control |= T_REMDEV; 18821da177e4SLinus Torvalds if_unlock(t); 18831da177e4SLinus Torvalds } 18841da177e4SLinus Torvalds break; 18851da177e4SLinus Torvalds } 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds return pkt_dev; 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds 189095ed63f7SArthur Kepner /* 189195ed63f7SArthur Kepner * mark a device for removal 189295ed63f7SArthur Kepner */ 189339df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname) 18941da177e4SLinus Torvalds { 18951da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 189695ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 189795ed63f7SArthur Kepner int i = 0; 189895ed63f7SArthur Kepner 18996146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1900f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 190195ed63f7SArthur Kepner 190295ed63f7SArthur Kepner while (1) { 190395ed63f7SArthur Kepner 190495ed63f7SArthur Kepner pkt_dev = __pktgen_NN_threads(ifname, REMOVE); 1905222f1806SLuiz Capitulino if (pkt_dev == NULL) 1906222f1806SLuiz Capitulino break; /* success */ 190795ed63f7SArthur Kepner 19086146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1909f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1910f9467eaeSJoe Perches __func__, ifname); 191195ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19126146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 191395ed63f7SArthur Kepner 191495ed63f7SArthur Kepner if (++i >= max_tries) { 1915f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1916f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 191795ed63f7SArthur Kepner break; 191895ed63f7SArthur Kepner } 191995ed63f7SArthur Kepner 192095ed63f7SArthur Kepner } 192195ed63f7SArthur Kepner 19226146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 192339df232fSStephen Hemminger } 192495ed63f7SArthur Kepner 192539df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev) 192639df232fSStephen Hemminger { 192739df232fSStephen Hemminger struct pktgen_thread *t; 192839df232fSStephen Hemminger 192939df232fSStephen Hemminger list_for_each_entry(t, &pktgen_threads, th_list) { 193039df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 193139df232fSStephen Hemminger 193239df232fSStephen Hemminger list_for_each_entry(pkt_dev, &t->if_list, list) { 193339df232fSStephen Hemminger if (pkt_dev->odev != dev) 193439df232fSStephen Hemminger continue; 193539df232fSStephen Hemminger 193639df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 193739df232fSStephen Hemminger 19382975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19392975315bSAlexey Dobriyan pg_proc_dir, 19402975315bSAlexey Dobriyan &pktgen_if_fops, 19412975315bSAlexey Dobriyan pkt_dev); 194239df232fSStephen Hemminger if (!pkt_dev->entry) 1943f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1944f9467eaeSJoe Perches dev->name); 194539df232fSStephen Hemminger break; 194639df232fSStephen Hemminger } 194739df232fSStephen Hemminger } 19481da177e4SLinus Torvalds } 19491da177e4SLinus Torvalds 1950222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1951222f1806SLuiz Capitulino unsigned long event, void *ptr) 19521da177e4SLinus Torvalds { 195339df232fSStephen Hemminger struct net_device *dev = ptr; 19541da177e4SLinus Torvalds 1955721499e8SYOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 1956e9dc8653SEric W. Biederman return NOTIFY_DONE; 1957e9dc8653SEric W. Biederman 19581da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19591da177e4SLinus Torvalds * as we run under the RTNL lock. 19601da177e4SLinus Torvalds */ 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds switch (event) { 196339df232fSStephen Hemminger case NETDEV_CHANGENAME: 196439df232fSStephen Hemminger pktgen_change_name(dev); 19651da177e4SLinus Torvalds break; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds case NETDEV_UNREGISTER: 196895ed63f7SArthur Kepner pktgen_mark_device(dev->name); 19691da177e4SLinus Torvalds break; 19703ff50b79SStephen Hemminger } 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds return NOTIFY_DONE; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds 197563adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, 197663adc6fbSStephen Hemminger const char *ifname) 1977e6fce5b9SRobert Olsson { 1978e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1979d6182223SPaul Gortmaker int i; 1980e6fce5b9SRobert Olsson 1981e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 1982e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 1983e6fce5b9SRobert Olsson break; 1984e6fce5b9SRobert Olsson 1985e6fce5b9SRobert Olsson b[i] = ifname[i]; 1986e6fce5b9SRobert Olsson } 1987e6fce5b9SRobert Olsson b[i] = 0; 1988e6fce5b9SRobert Olsson 1989e6fce5b9SRobert Olsson return dev_get_by_name(&init_net, b); 1990e6fce5b9SRobert Olsson } 1991e6fce5b9SRobert Olsson 1992e6fce5b9SRobert Olsson 19931da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 19941da177e4SLinus Torvalds 199539df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) 1996222f1806SLuiz Capitulino { 19971da177e4SLinus Torvalds struct net_device *odev; 199839df232fSStephen Hemminger int err; 19991da177e4SLinus Torvalds 20001da177e4SLinus Torvalds /* Clean old setups */ 20011da177e4SLinus Torvalds if (pkt_dev->odev) { 20021da177e4SLinus Torvalds dev_put(pkt_dev->odev); 20031da177e4SLinus Torvalds pkt_dev->odev = NULL; 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds 2006e6fce5b9SRobert Olsson odev = pktgen_dev_get_by_name(pkt_dev, ifname); 20071da177e4SLinus Torvalds if (!odev) { 2008f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 200939df232fSStephen Hemminger return -ENODEV; 20101da177e4SLinus Torvalds } 201139df232fSStephen Hemminger 20121da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2013f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 201439df232fSStephen Hemminger err = -EINVAL; 201539df232fSStephen Hemminger } else if (!netif_running(odev)) { 2016f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 201739df232fSStephen Hemminger err = -ENETDOWN; 201839df232fSStephen Hemminger } else { 20191da177e4SLinus Torvalds pkt_dev->odev = odev; 202039df232fSStephen Hemminger return 0; 202139df232fSStephen Hemminger } 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds dev_put(odev); 202439df232fSStephen Hemminger return err; 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds 20271da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20281da177e4SLinus Torvalds * structure to have the right information to create/send packets 20291da177e4SLinus Torvalds */ 20301da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20311da177e4SLinus Torvalds { 203264c00d81SAndrew Gallatin int ntxq; 203364c00d81SAndrew Gallatin 20341da177e4SLinus Torvalds if (!pkt_dev->odev) { 2035f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2036222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2037222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20381da177e4SLinus Torvalds return; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 204164c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 204264c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2043bfdbc0acSRobert Olsson 204464c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2045f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 204688271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2047593f63b0SEric Dumazet pkt_dev->odevname); 204864c00d81SAndrew Gallatin pkt_dev->queue_map_min = ntxq - 1; 204964c00d81SAndrew Gallatin } 205088271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2051f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 205288271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2053593f63b0SEric Dumazet pkt_dev->odevname); 205464c00d81SAndrew Gallatin pkt_dev->queue_map_max = ntxq - 1; 205564c00d81SAndrew Gallatin } 205664c00d81SAndrew Gallatin 20571da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20581da177e4SLinus Torvalds 2059f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 2060f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); 20611da177e4SLinus Torvalds 20621da177e4SLinus Torvalds /* Set up Dest MAC */ 2063f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds /* Set up pkt size */ 20661da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 20671da177e4SLinus Torvalds 20681da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20691da177e4SLinus Torvalds /* 20701da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 20711da177e4SLinus Torvalds * gets exported 20721da177e4SLinus Torvalds */ 20731da177e4SLinus Torvalds 20741da177e4SLinus Torvalds #ifdef NOTNOW 20751da177e4SLinus Torvalds int i, set = 0, err = 1; 20761da177e4SLinus Torvalds struct inet6_dev *idev; 20771da177e4SLinus Torvalds 20781da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20791da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20801da177e4SLinus Torvalds set = 1; 20811da177e4SLinus Torvalds break; 20821da177e4SLinus Torvalds } 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds if (!set) { 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds /* 20871da177e4SLinus Torvalds * Use linklevel address if unconfigured. 20881da177e4SLinus Torvalds * 20891da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 20901da177e4SLinus Torvalds */ 20911da177e4SLinus Torvalds 20928814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 209363adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 209463adc6fbSStephen Hemminger if (idev) { 20951da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 20961da177e4SLinus Torvalds 20971da177e4SLinus Torvalds read_lock_bh(&idev->lock); 2098222f1806SLuiz Capitulino for (ifp = idev->addr_list; ifp; 2099222f1806SLuiz Capitulino ifp = ifp->if_next) { 2100f64f9e71SJoe Perches if (ifp->scope == IFA_LINK && 2101f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 2102222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev-> 2103222f1806SLuiz Capitulino cur_in6_saddr, 2104222f1806SLuiz Capitulino &ifp->addr); 21051da177e4SLinus Torvalds err = 0; 21061da177e4SLinus Torvalds break; 21071da177e4SLinus Torvalds } 21081da177e4SLinus Torvalds } 21091da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 21101da177e4SLinus Torvalds } 21118814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2112222f1806SLuiz Capitulino if (err) 2113f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21141da177e4SLinus Torvalds } 21151da177e4SLinus Torvalds #endif 2116222f1806SLuiz Capitulino } else { 21171da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21181da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21191da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds struct in_device *in_dev; 21221da177e4SLinus Torvalds 21231da177e4SLinus Torvalds rcu_read_lock(); 2124e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21251da177e4SLinus Torvalds if (in_dev) { 21261da177e4SLinus Torvalds if (in_dev->ifa_list) { 2127222f1806SLuiz Capitulino pkt_dev->saddr_min = 2128222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 21291da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21301da177e4SLinus Torvalds } 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds rcu_read_unlock(); 2133222f1806SLuiz Capitulino } else { 21341da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21351da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21361da177e4SLinus Torvalds } 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21391da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds /* Initialize current values. */ 21421da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21431da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21441da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21451da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21461da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21471da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21481da177e4SLinus Torvalds pkt_dev->nflows = 0; 21491da177e4SLinus Torvalds } 21501da177e4SLinus Torvalds 21511da177e4SLinus Torvalds 2152fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2153fd29cf72SStephen Hemminger { 2154ef87979cSStephen Hemminger ktime_t start_time, end_time; 2155417bc4b8SEric Dumazet s64 remaining; 21562bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2157fd29cf72SStephen Hemminger 21582bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21592bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2160fd29cf72SStephen Hemminger 216143d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2162417bc4b8SEric Dumazet if (remaining <= 0) { 2163417bc4b8SEric Dumazet pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21641da177e4SLinus Torvalds return; 2165417bc4b8SEric Dumazet } 21662bc481cfSStephen Hemminger 2167ef87979cSStephen Hemminger start_time = ktime_now(); 216843d28b65SDaniel Turull if (remaining < 100000) 216943d28b65SDaniel Turull ndelay(remaining); /* really small just spin */ 21702bc481cfSStephen Hemminger else { 21712bc481cfSStephen Hemminger /* see do_nanosleep */ 21722bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 21732bc481cfSStephen Hemminger do { 21742bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21752bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 21762bc481cfSStephen Hemminger if (!hrtimer_active(&t.timer)) 21772bc481cfSStephen Hemminger t.task = NULL; 21782bc481cfSStephen Hemminger 21792bc481cfSStephen Hemminger if (likely(t.task)) 21801da177e4SLinus Torvalds schedule(); 21811da177e4SLinus Torvalds 21822bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 21832bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 21842bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 21851da177e4SLinus Torvalds } 2186ef87979cSStephen Hemminger end_time = ktime_now(); 2187ef87979cSStephen Hemminger 2188ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 218907a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21901da177e4SLinus Torvalds } 21911da177e4SLinus Torvalds 219216dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 219316dab72fSJamal Hadi Salim { 2194a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 219516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 219616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 219716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 219816dab72fSJamal Hadi Salim } 219916dab72fSJamal Hadi Salim 2200648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2201007a531bSJamal Hadi Salim { 2202648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2203007a531bSJamal Hadi Salim } 2204007a531bSJamal Hadi Salim 2205007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2206007a531bSJamal Hadi Salim { 2207007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2208007a531bSJamal Hadi Salim 2209007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2210007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2211007a531bSJamal Hadi Salim /* reset time */ 2212007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22131211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2214007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2215007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2216007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2217007a531bSJamal Hadi Salim } 2218007a531bSJamal Hadi Salim } else { 2219007a531bSJamal Hadi Salim flow = random32() % pkt_dev->cflows; 22201211a645SRobert Olsson pkt_dev->curfl = flow; 2221007a531bSJamal Hadi Salim 22221211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2223007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22241211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22251211a645SRobert Olsson } 2226007a531bSJamal Hadi Salim } 2227007a531bSJamal Hadi Salim 2228007a531bSJamal Hadi Salim return pkt_dev->curfl; 2229007a531bSJamal Hadi Salim } 2230007a531bSJamal Hadi Salim 2231a553e4a6SJamal Hadi Salim 2232a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2233a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2234a553e4a6SJamal Hadi Salim * we go look for it ... 2235a553e4a6SJamal Hadi Salim */ 2236bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2237fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2238a553e4a6SJamal Hadi Salim { 2239a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 2240a553e4a6SJamal Hadi Salim if (!x) { 2241a553e4a6SJamal Hadi Salim /*slow path: we dont already have xfrm_state*/ 2242bd55775cSJamal Hadi Salim x = xfrm_stateonly_find(&init_net, DUMMY_MARK, 22435447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2244a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2245a553e4a6SJamal Hadi Salim AF_INET, 2246a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2247a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2248a553e4a6SJamal Hadi Salim if (x) { 2249a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2250a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2251a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2252a553e4a6SJamal Hadi Salim } 2253a553e4a6SJamal Hadi Salim 2254a553e4a6SJamal Hadi Salim } 2255a553e4a6SJamal Hadi Salim } 2256a553e4a6SJamal Hadi Salim #endif 2257fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2258fd2ea0a7SDavid S. Miller { 2259e6fce5b9SRobert Olsson 2260e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2261e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2262e6fce5b9SRobert Olsson 2263896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2264fd2ea0a7SDavid S. Miller __u16 t; 2265fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 2266fd2ea0a7SDavid S. Miller t = random32() % 2267fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2268fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2269fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2270fd2ea0a7SDavid S. Miller } else { 2271fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2272fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2273fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2274fd2ea0a7SDavid S. Miller } 2275fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2276fd2ea0a7SDavid S. Miller } 2277bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2278fd2ea0a7SDavid S. Miller } 2279fd2ea0a7SDavid S. Miller 22801da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 22811da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 22821da177e4SLinus Torvalds */ 2283222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2284222f1806SLuiz Capitulino { 22851da177e4SLinus Torvalds __u32 imn; 22861da177e4SLinus Torvalds __u32 imx; 22871da177e4SLinus Torvalds int flow = 0; 22881da177e4SLinus Torvalds 2289007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2290007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 22911da177e4SLinus Torvalds 22921da177e4SLinus Torvalds /* Deal with source MAC */ 22931da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 22941da177e4SLinus Torvalds __u32 mc; 22951da177e4SLinus Torvalds __u32 tmp; 22961da177e4SLinus Torvalds 22971da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 22985fa6fc76SStephen Hemminger mc = random32() % pkt_dev->src_mac_count; 22991da177e4SLinus Torvalds else { 23001da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2301ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2302222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23031da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23071da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23081da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23091da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23101da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23111da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23121da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23131da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23141da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23151da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23161da177e4SLinus Torvalds } 23171da177e4SLinus Torvalds 23181da177e4SLinus Torvalds /* Deal with Destination MAC */ 23191da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23201da177e4SLinus Torvalds __u32 mc; 23211da177e4SLinus Torvalds __u32 tmp; 23221da177e4SLinus Torvalds 23231da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 23245fa6fc76SStephen Hemminger mc = random32() % pkt_dev->dst_mac_count; 23251da177e4SLinus Torvalds 23261da177e4SLinus Torvalds else { 23271da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2328ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2329222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23301da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds } 23331da177e4SLinus Torvalds 23341da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23351da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23361da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23371da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23381da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23391da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23401da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23411da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23421da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23431da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23441da177e4SLinus Torvalds } 23451da177e4SLinus Torvalds 2346ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 2347ca6549afSSteven Whitehouse unsigned i; 2348ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2349ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2350ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 23515fa6fc76SStephen Hemminger ((__force __be32)random32() & 2352ca6549afSSteven Whitehouse htonl(0x000fffff)); 2353ca6549afSSteven Whitehouse } 2354ca6549afSSteven Whitehouse 235534954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 23565fa6fc76SStephen Hemminger pkt_dev->vlan_id = random32() & (4096-1); 235734954ddcSFrancesco Fondelli } 235834954ddcSFrancesco Fondelli 235934954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 23605fa6fc76SStephen Hemminger pkt_dev->svlan_id = random32() & (4096 - 1); 236134954ddcSFrancesco Fondelli } 236234954ddcSFrancesco Fondelli 23631da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23641da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 23655fa6fc76SStephen Hemminger pkt_dev->cur_udp_src = random32() % 23665fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23675fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23681da177e4SLinus Torvalds 23691da177e4SLinus Torvalds else { 23701da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 23711da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23721da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 23761da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23771da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 23785fa6fc76SStephen Hemminger pkt_dev->cur_udp_dst = random32() % 23795fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23805fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2381222f1806SLuiz Capitulino } else { 23821da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 23831da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 23841da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 23851da177e4SLinus Torvalds } 23861da177e4SLinus Torvalds } 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 23891da177e4SLinus Torvalds 239063adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 239163adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 239263adc6fbSStephen Hemminger if (imn < imx) { 23931da177e4SLinus Torvalds __u32 t; 23941da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 23955fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 23961da177e4SLinus Torvalds else { 23971da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 23981da177e4SLinus Torvalds t++; 239963adc6fbSStephen Hemminger if (t > imx) 24001da177e4SLinus Torvalds t = imn; 240163adc6fbSStephen Hemminger 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24041da177e4SLinus Torvalds } 24051da177e4SLinus Torvalds 2406007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24071da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24081da177e4SLinus Torvalds } else { 2409252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2410252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2411252e3346SAl Viro if (imn < imx) { 24121da177e4SLinus Torvalds __u32 t; 2413252e3346SAl Viro __be32 s; 24141da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24151da177e4SLinus Torvalds 24165fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2417252e3346SAl Viro s = htonl(t); 24181da177e4SLinus Torvalds 241921cf2253SJoe Perches while (ipv4_is_loopback(s) || 242021cf2253SJoe Perches ipv4_is_multicast(s) || 24211e637c74SJan Engelhardt ipv4_is_lbcast(s) || 242221cf2253SJoe Perches ipv4_is_zeronet(s) || 242321cf2253SJoe Perches ipv4_is_local_multicast(s)) { 24245fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2425252e3346SAl Viro s = htonl(t); 24261da177e4SLinus Torvalds } 2427252e3346SAl Viro pkt_dev->cur_daddr = s; 2428252e3346SAl Viro } else { 24291da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24301da177e4SLinus Torvalds t++; 24311da177e4SLinus Torvalds if (t > imx) { 24321da177e4SLinus Torvalds t = imn; 24331da177e4SLinus Torvalds } 24341da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24351da177e4SLinus Torvalds } 24361da177e4SLinus Torvalds } 24371da177e4SLinus Torvalds if (pkt_dev->cflows) { 2438007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2439222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2440222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2441a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2442a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2443a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2444a553e4a6SJamal Hadi Salim #endif 24451da177e4SLinus Torvalds pkt_dev->nflows++; 24461da177e4SLinus Torvalds } 24471da177e4SLinus Torvalds } 2448222f1806SLuiz Capitulino } else { /* IPV6 * */ 2449222f1806SLuiz Capitulino 24501da177e4SLinus Torvalds if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 24511da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 24521da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 24531da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; 24541da177e4SLinus Torvalds else { 24551da177e4SLinus Torvalds int i; 24561da177e4SLinus Torvalds 24571da177e4SLinus Torvalds /* Only random destinations yet */ 24581da177e4SLinus Torvalds 24591da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24601da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 24615fa6fc76SStephen Hemminger (((__force __be32)random32() | 24621da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24631da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds } 24671da177e4SLinus Torvalds 24681da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24691da177e4SLinus Torvalds __u32 t; 24701da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 24715fa6fc76SStephen Hemminger t = random32() % 24725fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24735fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2474222f1806SLuiz Capitulino } else { 24751da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 24761da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 24771da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 24801da177e4SLinus Torvalds } 24811da177e4SLinus Torvalds 2482fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 248345b270f8SRobert Olsson 24841da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds 2487a553e4a6SJamal Hadi Salim 2488a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2489a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2490a553e4a6SJamal Hadi Salim { 2491a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2492a553e4a6SJamal Hadi Salim int err = 0; 2493a553e4a6SJamal Hadi Salim struct iphdr *iph; 2494a553e4a6SJamal Hadi Salim 2495a553e4a6SJamal Hadi Salim if (!x) 2496a553e4a6SJamal Hadi Salim return 0; 2497a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2498a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2499a553e4a6SJamal Hadi Salim if (x->props.mode != XFRM_MODE_TRANSPORT) 2500a553e4a6SJamal Hadi Salim return 0; 2501a553e4a6SJamal Hadi Salim 2502a553e4a6SJamal Hadi Salim spin_lock(&x->lock); 2503a553e4a6SJamal Hadi Salim iph = ip_hdr(skb); 2504a553e4a6SJamal Hadi Salim 250513996378SHerbert Xu err = x->outer_mode->output(x, skb); 2506a553e4a6SJamal Hadi Salim if (err) 2507a553e4a6SJamal Hadi Salim goto error; 2508a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 2509a553e4a6SJamal Hadi Salim if (err) 2510a553e4a6SJamal Hadi Salim goto error; 2511a553e4a6SJamal Hadi Salim 2512a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2513a553e4a6SJamal Hadi Salim x->curlft.packets++; 2514a553e4a6SJamal Hadi Salim error: 2515a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2516a553e4a6SJamal Hadi Salim return err; 2517a553e4a6SJamal Hadi Salim } 2518a553e4a6SJamal Hadi Salim 2519475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2520a553e4a6SJamal Hadi Salim { 2521a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2522a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2523d6182223SPaul Gortmaker int i; 2524d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2525a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2526a553e4a6SJamal Hadi Salim if (x) { 2527a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2528a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2529a553e4a6SJamal Hadi Salim } 2530a553e4a6SJamal Hadi Salim } 2531a553e4a6SJamal Hadi Salim } 2532a553e4a6SJamal Hadi Salim } 2533a553e4a6SJamal Hadi Salim 2534475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2535a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2536a553e4a6SJamal Hadi Salim { 2537a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2538a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2539a553e4a6SJamal Hadi Salim int nhead = 0; 2540a553e4a6SJamal Hadi Salim if (x) { 2541a553e4a6SJamal Hadi Salim int ret; 2542a553e4a6SJamal Hadi Salim __u8 *eth; 2543a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2544a553e4a6SJamal Hadi Salim if (nhead > 0) { 2545a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2546a553e4a6SJamal Hadi Salim if (ret < 0) { 2547f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2548f9467eaeSJoe Perches ret); 2549b4bb4ac8SIlpo Järvinen goto err; 2550a553e4a6SJamal Hadi Salim } 2551a553e4a6SJamal Hadi Salim } 2552a553e4a6SJamal Hadi Salim 2553a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2554a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2555a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2556a553e4a6SJamal Hadi Salim if (ret) { 2557f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2558b4bb4ac8SIlpo Järvinen goto err; 2559a553e4a6SJamal Hadi Salim } 2560a553e4a6SJamal Hadi Salim /* restore ll */ 2561a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2562a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2563a553e4a6SJamal Hadi Salim *(u16 *) ð[12] = protocol; 2564a553e4a6SJamal Hadi Salim } 2565a553e4a6SJamal Hadi Salim } 2566a553e4a6SJamal Hadi Salim return 1; 2567b4bb4ac8SIlpo Järvinen err: 2568b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2569b4bb4ac8SIlpo Järvinen return 0; 2570a553e4a6SJamal Hadi Salim } 2571a553e4a6SJamal Hadi Salim #endif 2572a553e4a6SJamal Hadi Salim 2573ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2574ca6549afSSteven Whitehouse { 2575ca6549afSSteven Whitehouse unsigned i; 257663adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2577ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 257863adc6fbSStephen Hemminger 2579ca6549afSSteven Whitehouse mpls--; 2580ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2581ca6549afSSteven Whitehouse } 2582ca6549afSSteven Whitehouse 25830f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 25840f37c605SAl Viro unsigned int prio) 25850f37c605SAl Viro { 25860f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 25870f37c605SAl Viro } 25880f37c605SAl Viro 25891da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 25901da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 25911da177e4SLinus Torvalds { 25921da177e4SLinus Torvalds struct sk_buff *skb = NULL; 25931da177e4SLinus Torvalds __u8 *eth; 25941da177e4SLinus Torvalds struct udphdr *udph; 25951da177e4SLinus Torvalds int datalen, iplen; 25961da177e4SLinus Torvalds struct iphdr *iph; 25971da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2598d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2599ca6549afSSteven Whitehouse __be32 *mpls; 260034954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 260134954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 260234954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 260334954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2604fd2ea0a7SDavid S. Miller u16 queue_map; 2605ca6549afSSteven Whitehouse 2606ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2607d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 26081da177e4SLinus Torvalds 260934954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2610d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 261134954ddcSFrancesco Fondelli 261264053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 261364053beeSRobert Olsson * fields. 261464053beeSRobert Olsson */ 2615fd2ea0a7SDavid S. Miller queue_map = pkt_dev->cur_queue_map; 261664053beeSRobert Olsson mod_cur_headers(pkt_dev); 261764053beeSRobert Olsson 26187ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2619e99b99b4SRobert Olsson 2620e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) { 2621e99b99b4SRobert Olsson int node; 2622e99b99b4SRobert Olsson 2623e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 2624e99b99b4SRobert Olsson node = pkt_dev->node; 2625e99b99b4SRobert Olsson else 2626e99b99b4SRobert Olsson node = numa_node_id(); 2627e99b99b4SRobert Olsson 2628e99b99b4SRobert Olsson skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64 2629e99b99b4SRobert Olsson + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node); 2630e99b99b4SRobert Olsson if (likely(skb)) { 2631e99b99b4SRobert Olsson skb_reserve(skb, NET_SKB_PAD); 2632e99b99b4SRobert Olsson skb->dev = odev; 2633e99b99b4SRobert Olsson } 2634e99b99b4SRobert Olsson } 2635e99b99b4SRobert Olsson else 2636e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2637e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2638e470757dSStephen Hemminger + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); 2639e99b99b4SRobert Olsson 26401da177e4SLinus Torvalds if (!skb) { 26411da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 26421da177e4SLinus Torvalds return NULL; 26431da177e4SLinus Torvalds } 26441da177e4SLinus Torvalds 26457ac5459eSDavid S. Miller skb_reserve(skb, datalen); 26461da177e4SLinus Torvalds 26471da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 26481da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2649ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2650ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2651ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 265234954ddcSFrancesco Fondelli 265334954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 265434954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 265534954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26560f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 26570f37c605SAl Viro pkt_dev->svlan_cfi, 26580f37c605SAl Viro pkt_dev->svlan_p); 265934954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2660d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 266134954ddcSFrancesco Fondelli } 266234954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26630f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 26640f37c605SAl Viro pkt_dev->vlan_cfi, 26650f37c605SAl Viro pkt_dev->vlan_p); 266634954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2667d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 266834954ddcSFrancesco Fondelli } 266934954ddcSFrancesco Fondelli 267027a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2671b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct iphdr); 2672ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2673fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 2674ddc7b8e3SArnaldo Carvalho de Melo iph = ip_hdr(skb); 2675ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 26761da177e4SLinus Torvalds 26771da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2678252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 26791da177e4SLinus Torvalds 2680ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2681ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 268216dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 26831da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 26841da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 26851da177e4SLinus Torvalds 26861da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 26871da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 26881da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 26891da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 26901da177e4SLinus Torvalds 26911da177e4SLinus Torvalds iph->ihl = 5; 26921da177e4SLinus Torvalds iph->version = 4; 26931da177e4SLinus Torvalds iph->ttl = 32; 26941ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 26951da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 26961da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 26971da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 269866ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 269966ed1e5eSEric Dumazet pkt_dev->ip_id++; 27001da177e4SLinus Torvalds iph->frag_off = 0; 27011da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 27021da177e4SLinus Torvalds iph->tot_len = htons(iplen); 27031da177e4SLinus Torvalds iph->check = 0; 27041da177e4SLinus Torvalds iph->check = ip_fast_csum((void *)iph, iph->ihl); 2705ca6549afSSteven Whitehouse skb->protocol = protocol; 2706b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 270716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 27081da177e4SLinus Torvalds skb->dev = odev; 27091da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 27101da177e4SLinus Torvalds 271166ed1e5eSEric Dumazet if (pkt_dev->nfrags <= 0) { 27121da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 271366ed1e5eSEric Dumazet memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); 271466ed1e5eSEric Dumazet } else { 27151da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 271666ed1e5eSEric Dumazet int i, len; 27171da177e4SLinus Torvalds 27181da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 27191da177e4SLinus Torvalds 27201da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 27211da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 27221da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 272366ed1e5eSEric Dumazet len = datalen - frags * PAGE_SIZE; 272466ed1e5eSEric Dumazet memset(skb_put(skb, len), 0, len); 27251da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 27261da177e4SLinus Torvalds } 27271da177e4SLinus Torvalds 27281da177e4SLinus Torvalds i = 0; 27291da177e4SLinus Torvalds while (datalen > 0) { 273066ed1e5eSEric Dumazet struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); 27311da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 27321da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 27331da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 27341da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 27351da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 27361da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 27371da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 27381da177e4SLinus Torvalds i++; 27391da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27401da177e4SLinus Torvalds } 27411da177e4SLinus Torvalds 27421da177e4SLinus Torvalds while (i < frags) { 27431da177e4SLinus Torvalds int rem; 27441da177e4SLinus Torvalds 27451da177e4SLinus Torvalds if (i == 0) 27461da177e4SLinus Torvalds break; 27471da177e4SLinus Torvalds 27481da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 27491da177e4SLinus Torvalds if (rem == 0) 27501da177e4SLinus Torvalds break; 27511da177e4SLinus Torvalds 27521da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 27531da177e4SLinus Torvalds 2754222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2755222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 27561da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2757222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2758222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2759222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2760222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 27611da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 27621da177e4SLinus Torvalds i++; 27631da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27641da177e4SLinus Torvalds } 27651da177e4SLinus Torvalds } 27661da177e4SLinus Torvalds 276763adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 276863adc6fbSStephen Hemminger * convert them to network byte order 276963adc6fbSStephen Hemminger */ 27701da177e4SLinus Torvalds if (pgh) { 27711da177e4SLinus Torvalds struct timeval timestamp; 27721da177e4SLinus Torvalds 27731da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 27741da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 27751da177e4SLinus Torvalds 27761da177e4SLinus Torvalds do_gettimeofday(×tamp); 27771da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 27781da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 27791da177e4SLinus Torvalds } 27801da177e4SLinus Torvalds 2781a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2782a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2783a553e4a6SJamal Hadi Salim return NULL; 2784a553e4a6SJamal Hadi Salim #endif 2785a553e4a6SJamal Hadi Salim 27861da177e4SLinus Torvalds return skb; 27871da177e4SLinus Torvalds } 27881da177e4SLinus Torvalds 27891da177e4SLinus Torvalds /* 27901da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 27911da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 27921da177e4SLinus Torvalds * 27931da177e4SLinus Torvalds * Slightly modified for kernel. 27941da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 27951da177e4SLinus Torvalds * --ro 27961da177e4SLinus Torvalds */ 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]) 27991da177e4SLinus Torvalds { 28001da177e4SLinus Torvalds unsigned int i; 28011da177e4SLinus Torvalds unsigned int len = 0; 28021da177e4SLinus Torvalds unsigned long u; 28031da177e4SLinus Torvalds char suffix[16]; 28041da177e4SLinus Torvalds unsigned int prefixlen = 0; 28051da177e4SLinus Torvalds unsigned int suffixlen = 0; 2806252e3346SAl Viro __be32 tmp; 2807cfcabdccSStephen Hemminger char *pos; 28081da177e4SLinus Torvalds 2809222f1806SLuiz Capitulino for (i = 0; i < 16; i++) 2810222f1806SLuiz Capitulino ip[i] = 0; 28111da177e4SLinus Torvalds 28121da177e4SLinus Torvalds for (;;) { 28131da177e4SLinus Torvalds if (*s == ':') { 28141da177e4SLinus Torvalds len++; 28151da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 28161da177e4SLinus Torvalds s += 2; 28171da177e4SLinus Torvalds len++; 28181da177e4SLinus Torvalds break; 28191da177e4SLinus Torvalds } 28201da177e4SLinus Torvalds s++; 28211da177e4SLinus Torvalds } 28221da177e4SLinus Torvalds 2823cfcabdccSStephen Hemminger u = simple_strtoul(s, &pos, 16); 2824cfcabdccSStephen Hemminger i = pos - s; 2825222f1806SLuiz Capitulino if (!i) 2826222f1806SLuiz Capitulino return 0; 28271da177e4SLinus Torvalds if (prefixlen == 12 && s[i] == '.') { 28281da177e4SLinus Torvalds 28291da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 28301da177e4SLinus Torvalds 28311da177e4SLinus Torvalds tmp = in_aton(s); 28321da177e4SLinus Torvalds memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); 28331da177e4SLinus Torvalds return i + len; 28341da177e4SLinus Torvalds } 28351da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 28361da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2837222f1806SLuiz Capitulino s += i; 2838222f1806SLuiz Capitulino len += i; 28391da177e4SLinus Torvalds if (prefixlen == 16) 28401da177e4SLinus Torvalds return len; 28411da177e4SLinus Torvalds } 28421da177e4SLinus Torvalds 28431da177e4SLinus Torvalds /* part 2, after "::" */ 28441da177e4SLinus Torvalds for (;;) { 28451da177e4SLinus Torvalds if (*s == ':') { 28461da177e4SLinus Torvalds if (suffixlen == 0) 28471da177e4SLinus Torvalds break; 28481da177e4SLinus Torvalds s++; 28491da177e4SLinus Torvalds len++; 28501da177e4SLinus Torvalds } else if (suffixlen != 0) 28511da177e4SLinus Torvalds break; 2852cfcabdccSStephen Hemminger 2853cfcabdccSStephen Hemminger u = simple_strtol(s, &pos, 16); 2854cfcabdccSStephen Hemminger i = pos - s; 28551da177e4SLinus Torvalds if (!i) { 2856222f1806SLuiz Capitulino if (*s) 2857222f1806SLuiz Capitulino len--; 28581da177e4SLinus Torvalds break; 28591da177e4SLinus Torvalds } 28601da177e4SLinus Torvalds if (suffixlen + prefixlen <= 12 && s[i] == '.') { 28611da177e4SLinus Torvalds tmp = in_aton(s); 2862222f1806SLuiz Capitulino memcpy((struct in_addr *)(suffix + suffixlen), &tmp, 2863222f1806SLuiz Capitulino sizeof(tmp)); 28641da177e4SLinus Torvalds suffixlen += 4; 28651da177e4SLinus Torvalds len += strlen(s); 28661da177e4SLinus Torvalds break; 28671da177e4SLinus Torvalds } 28681da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 28691da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2870222f1806SLuiz Capitulino s += i; 2871222f1806SLuiz Capitulino len += i; 28721da177e4SLinus Torvalds if (prefixlen + suffixlen == 16) 28731da177e4SLinus Torvalds break; 28741da177e4SLinus Torvalds } 28751da177e4SLinus Torvalds for (i = 0; i < suffixlen; i++) 28761da177e4SLinus Torvalds ip[16 - suffixlen + i] = suffix[i]; 28771da177e4SLinus Torvalds return len; 28781da177e4SLinus Torvalds } 28791da177e4SLinus Torvalds 2880222f1806SLuiz Capitulino static char tohex(char hexdigit) 2881222f1806SLuiz Capitulino { 28821da177e4SLinus Torvalds return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 2885222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i) 2886222f1806SLuiz Capitulino { 28871da177e4SLinus Torvalds char *bak = s; 2888222f1806SLuiz Capitulino *s = tohex((i >> 12) & 0xf); 2889222f1806SLuiz Capitulino if (s != bak || *s != '0') 2890222f1806SLuiz Capitulino ++s; 2891222f1806SLuiz Capitulino *s = tohex((i >> 8) & 0xf); 2892222f1806SLuiz Capitulino if (s != bak || *s != '0') 2893222f1806SLuiz Capitulino ++s; 2894222f1806SLuiz Capitulino *s = tohex((i >> 4) & 0xf); 2895222f1806SLuiz Capitulino if (s != bak || *s != '0') 2896222f1806SLuiz Capitulino ++s; 28971da177e4SLinus Torvalds *s = tohex(i & 0xf); 28981da177e4SLinus Torvalds return s - bak + 1; 28991da177e4SLinus Torvalds } 29001da177e4SLinus Torvalds 2901222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16]) 2902222f1806SLuiz Capitulino { 29031da177e4SLinus Torvalds unsigned int len; 29041da177e4SLinus Torvalds unsigned int i; 29051da177e4SLinus Torvalds unsigned int temp; 29061da177e4SLinus Torvalds unsigned int compressing; 29071da177e4SLinus Torvalds int j; 29081da177e4SLinus Torvalds 2909222f1806SLuiz Capitulino len = 0; 2910222f1806SLuiz Capitulino compressing = 0; 29111da177e4SLinus Torvalds for (j = 0; j < 16; j += 2) { 29121da177e4SLinus Torvalds 29131da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 29141da177e4SLinus Torvalds if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { 29151da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr *)(ip + 12), s); 29161da177e4SLinus Torvalds temp = strlen(s); 29171da177e4SLinus Torvalds return len + temp; 29181da177e4SLinus Torvalds } 29191da177e4SLinus Torvalds #endif 29201da177e4SLinus Torvalds temp = ((unsigned long)(unsigned char)ip[j] << 8) + 29211da177e4SLinus Torvalds (unsigned long)(unsigned char)ip[j + 1]; 29221da177e4SLinus Torvalds if (temp == 0) { 29231da177e4SLinus Torvalds if (!compressing) { 29241da177e4SLinus Torvalds compressing = 1; 29251da177e4SLinus Torvalds if (j == 0) { 2926222f1806SLuiz Capitulino *s++ = ':'; 2927222f1806SLuiz Capitulino ++len; 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds } 29301da177e4SLinus Torvalds } else { 29311da177e4SLinus Torvalds if (compressing) { 29321da177e4SLinus Torvalds compressing = 0; 2933222f1806SLuiz Capitulino *s++ = ':'; 2934222f1806SLuiz Capitulino ++len; 29351da177e4SLinus Torvalds } 2936222f1806SLuiz Capitulino i = fmt_xlong(s, temp); 2937222f1806SLuiz Capitulino len += i; 2938222f1806SLuiz Capitulino s += i; 29391da177e4SLinus Torvalds if (j < 14) { 29401da177e4SLinus Torvalds *s++ = ':'; 29411da177e4SLinus Torvalds ++len; 29421da177e4SLinus Torvalds } 29431da177e4SLinus Torvalds } 29441da177e4SLinus Torvalds } 29451da177e4SLinus Torvalds if (compressing) { 2946222f1806SLuiz Capitulino *s++ = ':'; 2947222f1806SLuiz Capitulino ++len; 29481da177e4SLinus Torvalds } 29491da177e4SLinus Torvalds *s = 0; 29501da177e4SLinus Torvalds return len; 29511da177e4SLinus Torvalds } 29521da177e4SLinus Torvalds 29531da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29541da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29551da177e4SLinus Torvalds { 29561da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29571da177e4SLinus Torvalds __u8 *eth; 29581da177e4SLinus Torvalds struct udphdr *udph; 29591da177e4SLinus Torvalds int datalen; 29601da177e4SLinus Torvalds struct ipv6hdr *iph; 29611da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2962d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2963ca6549afSSteven Whitehouse __be32 *mpls; 296434954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 296534954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 296634954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 296734954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2968fd2ea0a7SDavid S. Miller u16 queue_map; 2969ca6549afSSteven Whitehouse 2970ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2971d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 29721da177e4SLinus Torvalds 297334954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2974d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 297534954ddcSFrancesco Fondelli 297664053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 297764053beeSRobert Olsson * fields. 297864053beeSRobert Olsson */ 2979fd2ea0a7SDavid S. Miller queue_map = pkt_dev->cur_queue_map; 298064053beeSRobert Olsson mod_cur_headers(pkt_dev); 298164053beeSRobert Olsson 2982e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2983e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2984e470757dSStephen Hemminger + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT); 29851da177e4SLinus Torvalds if (!skb) { 29861da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 29871da177e4SLinus Torvalds return NULL; 29881da177e4SLinus Torvalds } 29891da177e4SLinus Torvalds 29901da177e4SLinus Torvalds skb_reserve(skb, 16); 29911da177e4SLinus Torvalds 29921da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 29931da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2994ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2995ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2996ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 299734954ddcSFrancesco Fondelli 299834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 299934954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 300034954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30010f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30020f37c605SAl Viro pkt_dev->svlan_cfi, 30030f37c605SAl Viro pkt_dev->svlan_p); 300434954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3005d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 300634954ddcSFrancesco Fondelli } 300734954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30080f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30090f37c605SAl Viro pkt_dev->vlan_cfi, 30100f37c605SAl Viro pkt_dev->vlan_p); 301134954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3012d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 301334954ddcSFrancesco Fondelli } 301434954ddcSFrancesco Fondelli 301527a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 3016b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 3017ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 3018fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 3019ddc7b8e3SArnaldo Carvalho de Melo iph = ipv6_hdr(skb); 3020ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3023252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30241da177e4SLinus Torvalds 3025ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3026ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3027ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 302816dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30291da177e4SLinus Torvalds 30301da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 30311da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 30321da177e4SLinus Torvalds if (net_ratelimit()) 3033f9467eaeSJoe Perches pr_info("increased datalen to %d\n", datalen); 30341da177e4SLinus Torvalds } 30351da177e4SLinus Torvalds 30361da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30371da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 30381da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 30391da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 30401da177e4SLinus Torvalds 3041d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30421da177e4SLinus Torvalds 30431ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30441ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3045252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30461ca7768cSFrancesco Fondelli } 30471ca7768cSFrancesco Fondelli 30481da177e4SLinus Torvalds iph->hop_limit = 32; 30491da177e4SLinus Torvalds 30501da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 30511da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30521da177e4SLinus Torvalds 30531da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 30541da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 30551da177e4SLinus Torvalds 3056b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 305716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 3058ca6549afSSteven Whitehouse skb->protocol = protocol; 30591da177e4SLinus Torvalds skb->dev = odev; 30601da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 30631da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 30641da177e4SLinus Torvalds else { 30651da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 30661da177e4SLinus Torvalds int i; 30671da177e4SLinus Torvalds 30681da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 30691da177e4SLinus Torvalds 30701da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 30711da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 30721da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 30731da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 30741da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 30751da177e4SLinus Torvalds } 30761da177e4SLinus Torvalds 30771da177e4SLinus Torvalds i = 0; 30781da177e4SLinus Torvalds while (datalen > 0) { 30791da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 30801da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 30811da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 30821da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 30831da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 30841da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 30851da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 30861da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 30871da177e4SLinus Torvalds i++; 30881da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 30891da177e4SLinus Torvalds } 30901da177e4SLinus Torvalds 30911da177e4SLinus Torvalds while (i < frags) { 30921da177e4SLinus Torvalds int rem; 30931da177e4SLinus Torvalds 30941da177e4SLinus Torvalds if (i == 0) 30951da177e4SLinus Torvalds break; 30961da177e4SLinus Torvalds 30971da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 30981da177e4SLinus Torvalds if (rem == 0) 30991da177e4SLinus Torvalds break; 31001da177e4SLinus Torvalds 31011da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 31021da177e4SLinus Torvalds 3103222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 3104222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 31051da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 3106222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 3107222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 3108222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 3109222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 31101da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 31111da177e4SLinus Torvalds i++; 31121da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31131da177e4SLinus Torvalds } 31141da177e4SLinus Torvalds } 31151da177e4SLinus Torvalds 311663adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 311763adc6fbSStephen Hemminger * convert them to network byte order 311863adc6fbSStephen Hemminger * should we update cloned packets too ? 311963adc6fbSStephen Hemminger */ 31201da177e4SLinus Torvalds if (pgh) { 31211da177e4SLinus Torvalds struct timeval timestamp; 31221da177e4SLinus Torvalds 31231da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 31241da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 31251da177e4SLinus Torvalds 31261da177e4SLinus Torvalds do_gettimeofday(×tamp); 31271da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 31281da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 31291da177e4SLinus Torvalds } 313034954ddcSFrancesco Fondelli /* pkt_dev->seq_num++; FF: you really mean this? */ 31311da177e4SLinus Torvalds 31321da177e4SLinus Torvalds return skb; 31331da177e4SLinus Torvalds } 31341da177e4SLinus Torvalds 3135475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 31361da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 31371da177e4SLinus Torvalds { 31381da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 31391da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 31401da177e4SLinus Torvalds else 31411da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 31421da177e4SLinus Torvalds } 31431da177e4SLinus Torvalds 31441da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 31451da177e4SLinus Torvalds { 31461da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31471da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31481da177e4SLinus Torvalds pkt_dev->sofar = 0; 31491da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31501da177e4SLinus Torvalds pkt_dev->errors = 0; 31511da177e4SLinus Torvalds } 31521da177e4SLinus Torvalds 31531da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31541da177e4SLinus Torvalds 31551da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31561da177e4SLinus Torvalds { 3157c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31581da177e4SLinus Torvalds int started = 0; 31591da177e4SLinus Torvalds 3160f9467eaeSJoe Perches func_enter(); 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds if_lock(t); 3163c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 31641da177e4SLinus Torvalds 31651da177e4SLinus Torvalds /* 31661da177e4SLinus Torvalds * setup odev and create initial packet. 31671da177e4SLinus Torvalds */ 31681da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31691da177e4SLinus Torvalds 31701da177e4SLinus Torvalds if (pkt_dev->odev) { 31711da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31721da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 31731da177e4SLinus Torvalds pkt_dev->skb = NULL; 3174fd29cf72SStephen Hemminger pkt_dev->started_at = 3175fd29cf72SStephen Hemminger pkt_dev->next_tx = ktime_now(); 3176fd29cf72SStephen Hemminger 317716dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 31781da177e4SLinus Torvalds 31791da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 31801da177e4SLinus Torvalds started++; 3181222f1806SLuiz Capitulino } else 31821da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 31831da177e4SLinus Torvalds } 31841da177e4SLinus Torvalds if_unlock(t); 3185222f1806SLuiz Capitulino if (started) 3186222f1806SLuiz Capitulino t->control &= ~(T_STOP); 31871da177e4SLinus Torvalds } 31881da177e4SLinus Torvalds 31891da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 31901da177e4SLinus Torvalds { 3191cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 31921da177e4SLinus Torvalds 3193f9467eaeSJoe Perches func_enter(); 31941da177e4SLinus Torvalds 31956146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3196cdcdbe0bSLuiz Capitulino 3197cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 319895ed63f7SArthur Kepner t->control |= T_STOP; 3199cdcdbe0bSLuiz Capitulino 32006146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32011da177e4SLinus Torvalds } 32021da177e4SLinus Torvalds 3203648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 32041da177e4SLinus Torvalds { 3205648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 32061da177e4SLinus Torvalds 3207c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 3208648fda74SStephen Hemminger if (pkt_dev->running) 3209648fda74SStephen Hemminger return 1; 3210648fda74SStephen Hemminger return 0; 32111da177e4SLinus Torvalds } 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 32141da177e4SLinus Torvalds { 32151da177e4SLinus Torvalds if_lock(t); 32161da177e4SLinus Torvalds 32171da177e4SLinus Torvalds while (thread_is_running(t)) { 32181da177e4SLinus Torvalds 32191da177e4SLinus Torvalds if_unlock(t); 32201da177e4SLinus Torvalds 32211da177e4SLinus Torvalds msleep_interruptible(100); 32221da177e4SLinus Torvalds 32231da177e4SLinus Torvalds if (signal_pending(current)) 32241da177e4SLinus Torvalds goto signal; 32251da177e4SLinus Torvalds if_lock(t); 32261da177e4SLinus Torvalds } 32271da177e4SLinus Torvalds if_unlock(t); 32281da177e4SLinus Torvalds return 1; 32291da177e4SLinus Torvalds signal: 32301da177e4SLinus Torvalds return 0; 32311da177e4SLinus Torvalds } 32321da177e4SLinus Torvalds 32331da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 32341da177e4SLinus Torvalds { 3235cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32361da177e4SLinus Torvalds int sig = 1; 32371da177e4SLinus Torvalds 32386146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3239cdcdbe0bSLuiz Capitulino 3240cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 32411da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3242222f1806SLuiz Capitulino if (sig == 0) 3243222f1806SLuiz Capitulino break; 32441da177e4SLinus Torvalds } 3245cdcdbe0bSLuiz Capitulino 3246cdcdbe0bSLuiz Capitulino if (sig == 0) 3247cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32481da177e4SLinus Torvalds t->control |= (T_STOP); 3249cdcdbe0bSLuiz Capitulino 32506146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32511da177e4SLinus Torvalds return sig; 32521da177e4SLinus Torvalds } 32531da177e4SLinus Torvalds 32541da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 32551da177e4SLinus Torvalds { 3256cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32571da177e4SLinus Torvalds 3258f9467eaeSJoe Perches func_enter(); 32591da177e4SLinus Torvalds 32606146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 32611da177e4SLinus Torvalds 3262cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32631da177e4SLinus Torvalds t->control |= (T_RUN); 3264cdcdbe0bSLuiz Capitulino 32656146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32661da177e4SLinus Torvalds 326763adc6fbSStephen Hemminger /* Propagate thread->control */ 326863adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32691da177e4SLinus Torvalds 32701da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 32711da177e4SLinus Torvalds } 32721da177e4SLinus Torvalds 3273eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void) 3274eb37b41cSJesse Brandeburg { 3275eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3276eb37b41cSJesse Brandeburg 3277f9467eaeSJoe Perches func_enter(); 3278eb37b41cSJesse Brandeburg 3279eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3280eb37b41cSJesse Brandeburg 3281eb37b41cSJesse Brandeburg list_for_each_entry(t, &pktgen_threads, th_list) 3282eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3283eb37b41cSJesse Brandeburg 3284eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3285eb37b41cSJesse Brandeburg 328663adc6fbSStephen Hemminger /* Propagate thread->control */ 328763adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3288eb37b41cSJesse Brandeburg 3289eb37b41cSJesse Brandeburg pktgen_wait_all_threads_run(); 3290eb37b41cSJesse Brandeburg } 3291eb37b41cSJesse Brandeburg 32921da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 32931da177e4SLinus Torvalds { 3294fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 32951da177e4SLinus Torvalds char *p = pkt_dev->result; 3296fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3297fd29cf72SStephen Hemminger pkt_dev->started_at); 3298fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 32991da177e4SLinus Torvalds 3300fd29cf72SStephen Hemminger p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", 3301fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3302fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3303fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 33041da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 33051da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 33061da177e4SLinus Torvalds 3307fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3308fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 33091da177e4SLinus Torvalds 33101da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 33111da177e4SLinus Torvalds 33121da177e4SLinus Torvalds mbps = bps; 33131da177e4SLinus Torvalds do_div(mbps, 1000000); 33141da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 33151da177e4SLinus Torvalds (unsigned long long)pps, 33161da177e4SLinus Torvalds (unsigned long long)mbps, 33171da177e4SLinus Torvalds (unsigned long long)bps, 33181da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 33191da177e4SLinus Torvalds } 33201da177e4SLinus Torvalds 33211da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 33221da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 33231da177e4SLinus Torvalds { 3324222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 33251da177e4SLinus Torvalds 33261da177e4SLinus Torvalds if (!pkt_dev->running) { 3327f9467eaeSJoe Perches pr_warning("interface: %s is already stopped\n", 3328f9467eaeSJoe Perches pkt_dev->odevname); 33291da177e4SLinus Torvalds return -EINVAL; 33301da177e4SLinus Torvalds } 33311da177e4SLinus Torvalds 33323bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 33333bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3334fd29cf72SStephen Hemminger pkt_dev->stopped_at = ktime_now(); 33351da177e4SLinus Torvalds pkt_dev->running = 0; 33361da177e4SLinus Torvalds 333795ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 33381da177e4SLinus Torvalds 33391da177e4SLinus Torvalds return 0; 33401da177e4SLinus Torvalds } 33411da177e4SLinus Torvalds 33421da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 33431da177e4SLinus Torvalds { 3344c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 33451da177e4SLinus Torvalds 33461da177e4SLinus Torvalds if_lock(t); 33471da177e4SLinus Torvalds 3348c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3349c26a8016SLuiz Capitulino if (!pkt_dev->running) 3350222f1806SLuiz Capitulino continue; 3351222f1806SLuiz Capitulino if (best == NULL) 3352c26a8016SLuiz Capitulino best = pkt_dev; 3353fd29cf72SStephen Hemminger else if (ktime_lt(pkt_dev->next_tx, best->next_tx)) 3354c26a8016SLuiz Capitulino best = pkt_dev; 33551da177e4SLinus Torvalds } 33561da177e4SLinus Torvalds if_unlock(t); 33571da177e4SLinus Torvalds return best; 33581da177e4SLinus Torvalds } 33591da177e4SLinus Torvalds 3360222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3361222f1806SLuiz Capitulino { 3362c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33631da177e4SLinus Torvalds 3364f9467eaeSJoe Perches func_enter(); 33651da177e4SLinus Torvalds 33661da177e4SLinus Torvalds if_lock(t); 33671da177e4SLinus Torvalds 3368c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3369c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 337095ed63f7SArthur Kepner } 337195ed63f7SArthur Kepner 337295ed63f7SArthur Kepner if_unlock(t); 337395ed63f7SArthur Kepner } 337495ed63f7SArthur Kepner 337595ed63f7SArthur Kepner /* 337695ed63f7SArthur Kepner * one of our devices needs to be removed - find it 337795ed63f7SArthur Kepner * and remove it 337895ed63f7SArthur Kepner */ 337995ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 338095ed63f7SArthur Kepner { 3381c26a8016SLuiz Capitulino struct list_head *q, *n; 3382c26a8016SLuiz Capitulino struct pktgen_dev *cur; 338395ed63f7SArthur Kepner 3384f9467eaeSJoe Perches func_enter(); 338595ed63f7SArthur Kepner 338695ed63f7SArthur Kepner if_lock(t); 338795ed63f7SArthur Kepner 3388c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3389c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 339095ed63f7SArthur Kepner 3391222f1806SLuiz Capitulino if (!cur->removal_mark) 3392222f1806SLuiz Capitulino continue; 339395ed63f7SArthur Kepner 339495ed63f7SArthur Kepner kfree_skb(cur->skb); 339595ed63f7SArthur Kepner cur->skb = NULL; 339695ed63f7SArthur Kepner 339795ed63f7SArthur Kepner pktgen_remove_device(t, cur); 339895ed63f7SArthur Kepner 339995ed63f7SArthur Kepner break; 340095ed63f7SArthur Kepner } 34011da177e4SLinus Torvalds 34021da177e4SLinus Torvalds if_unlock(t); 34031da177e4SLinus Torvalds } 34041da177e4SLinus Torvalds 34051da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 34061da177e4SLinus Torvalds { 3407c26a8016SLuiz Capitulino struct list_head *q, *n; 3408c26a8016SLuiz Capitulino struct pktgen_dev *cur; 34091da177e4SLinus Torvalds 3410f9467eaeSJoe Perches func_enter(); 3411f9467eaeSJoe Perches 34121da177e4SLinus Torvalds /* Remove all devices, free mem */ 34131da177e4SLinus Torvalds 34141da177e4SLinus Torvalds if_lock(t); 34151da177e4SLinus Torvalds 3416c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3417c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 341895ed63f7SArthur Kepner 341995ed63f7SArthur Kepner kfree_skb(cur->skb); 342095ed63f7SArthur Kepner cur->skb = NULL; 342195ed63f7SArthur Kepner 34221da177e4SLinus Torvalds pktgen_remove_device(t, cur); 34231da177e4SLinus Torvalds } 34241da177e4SLinus Torvalds 34251da177e4SLinus Torvalds if_unlock(t); 34261da177e4SLinus Torvalds } 34271da177e4SLinus Torvalds 34281da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 34291da177e4SLinus Torvalds { 34301da177e4SLinus Torvalds /* Remove from the thread list */ 34311da177e4SLinus Torvalds 3432ee74baa7SDavid S. Miller remove_proc_entry(t->tsk->comm, pg_proc_dir); 34331da177e4SLinus Torvalds 34346146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 34351da177e4SLinus Torvalds 3436cdcdbe0bSLuiz Capitulino list_del(&t->th_list); 3437cdcdbe0bSLuiz Capitulino 34386146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 34391da177e4SLinus Torvalds } 34401da177e4SLinus Torvalds 3441ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 34423791decbSStephen Hemminger { 3443fd29cf72SStephen Hemminger ktime_t idle_start = ktime_now(); 34443791decbSStephen Hemminger schedule(); 3445fd29cf72SStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 34463791decbSStephen Hemminger } 34473791decbSStephen Hemminger 3448ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3449ef87979cSStephen Hemminger { 3450ef87979cSStephen Hemminger ktime_t idle_start = ktime_now(); 3451ef87979cSStephen Hemminger 3452ef87979cSStephen Hemminger while (atomic_read(&(pkt_dev->skb->users)) != 1) { 3453ef87979cSStephen Hemminger if (signal_pending(current)) 3454ef87979cSStephen Hemminger break; 3455ef87979cSStephen Hemminger 3456ef87979cSStephen Hemminger if (need_resched()) 3457ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3458ef87979cSStephen Hemminger else 3459ef87979cSStephen Hemminger cpu_relax(); 3460ef87979cSStephen Hemminger } 3461ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 3462ef87979cSStephen Hemminger } 3463fd29cf72SStephen Hemminger 3464475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34651da177e4SLinus Torvalds { 346600829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 34676fef4c0cSStephen Hemminger netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *) 346800829823SStephen Hemminger = odev->netdev_ops->ndo_start_xmit; 3469fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 3470fd2ea0a7SDavid S. Miller u16 queue_map; 34711da177e4SLinus Torvalds int ret; 34721da177e4SLinus Torvalds 3473ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3474ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34751da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34763791decbSStephen Hemminger return; 34771da177e4SLinus Torvalds } 34781da177e4SLinus Torvalds 3479ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3480ef87979cSStephen Hemminger * "never transmit" 3481ef87979cSStephen Hemminger */ 3482ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3483ef87979cSStephen Hemminger pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); 3484ef87979cSStephen Hemminger return; 3485ef87979cSStephen Hemminger } 3486ef87979cSStephen Hemminger 3487ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 34887d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 34897d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 34901da177e4SLinus Torvalds /* build a new pkt */ 34911da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 34921da177e4SLinus Torvalds 34931da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 34941da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3495f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 34961da177e4SLinus Torvalds schedule(); 34971da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 34983791decbSStephen Hemminger return; 34991da177e4SLinus Torvalds } 3500baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 35011da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 35021da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 35031da177e4SLinus Torvalds } 35041da177e4SLinus Torvalds 3505ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3506ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3507ef87979cSStephen Hemminger 3508fd2ea0a7SDavid S. Miller queue_map = skb_get_queue_mapping(pkt_dev->skb); 3509fd2ea0a7SDavid S. Miller txq = netdev_get_tx_queue(odev, queue_map); 3510fd2ea0a7SDavid S. Miller 3511fd2ea0a7SDavid S. Miller __netif_tx_lock_bh(txq); 35125b8db2f5SStephen Hemminger 35130835acfeSEric Dumazet if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) { 3514ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 35150835acfeSEric Dumazet pkt_dev->last_ok = 0; 35160835acfeSEric Dumazet goto unlock; 35170835acfeSEric Dumazet } 35180835acfeSEric Dumazet atomic_inc(&(pkt_dev->skb->users)); 351900829823SStephen Hemminger ret = (*xmit)(pkt_dev->skb, odev); 3520ef87979cSStephen Hemminger 35215b8db2f5SStephen Hemminger switch (ret) { 35225b8db2f5SStephen Hemminger case NETDEV_TX_OK: 352308baf561SEric Dumazet txq_trans_update(txq); 35241da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35251da177e4SLinus Torvalds pkt_dev->sofar++; 35261da177e4SLinus Torvalds pkt_dev->seq_num++; 3527baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 35285b8db2f5SStephen Hemminger break; 3529f466dba1SJohn Fastabend case NET_XMIT_DROP: 3530f466dba1SJohn Fastabend case NET_XMIT_CN: 3531f466dba1SJohn Fastabend case NET_XMIT_POLICED: 3532f466dba1SJohn Fastabend /* skb has been consumed */ 3533f466dba1SJohn Fastabend pkt_dev->errors++; 3534f466dba1SJohn Fastabend break; 35355b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 35365b8db2f5SStephen Hemminger if (net_ratelimit()) 35375b8db2f5SStephen Hemminger pr_info("pktgen: %s xmit error: %d\n", 3538593f63b0SEric Dumazet pkt_dev->odevname, ret); 35391da177e4SLinus Torvalds pkt_dev->errors++; 35405b8db2f5SStephen Hemminger /* fallthru */ 3541ef87979cSStephen Hemminger case NETDEV_TX_LOCKED: 35425b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35435b8db2f5SStephen Hemminger /* Retry it next time */ 35445b8db2f5SStephen Hemminger atomic_dec(&(pkt_dev->skb->users)); 35451da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35461da177e4SLinus Torvalds } 35470835acfeSEric Dumazet unlock: 3548fd2ea0a7SDavid S. Miller __netif_tx_unlock_bh(txq); 35491da177e4SLinus Torvalds 35501da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35511da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3552ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35531da177e4SLinus Torvalds 35541da177e4SLinus Torvalds /* Done with this */ 35551da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35561da177e4SLinus Torvalds } 35571da177e4SLinus Torvalds } 35581da177e4SLinus Torvalds 35591da177e4SLinus Torvalds /* 35601da177e4SLinus Torvalds * Main loop of the thread goes here 35611da177e4SLinus Torvalds */ 35621da177e4SLinus Torvalds 3563ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 35641da177e4SLinus Torvalds { 35651da177e4SLinus Torvalds DEFINE_WAIT(wait); 3566ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 35671da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 35681da177e4SLinus Torvalds int cpu = t->cpu; 35691da177e4SLinus Torvalds 3570ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 35711da177e4SLinus Torvalds 35721da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3573d3ede327SDenis V. Lunev complete(&t->start_done); 35741da177e4SLinus Torvalds 3575f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 35761da177e4SLinus Torvalds 3577ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 35781da177e4SLinus Torvalds 357983144186SRafael J. Wysocki set_freezable(); 358083144186SRafael J. Wysocki 3581ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3582ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3583ee74baa7SDavid S. Miller 3584ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 3585ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3586ef87979cSStephen Hemminger t->control != 0, 3587ef87979cSStephen Hemminger HZ/10); 35881b3f720bSRafael J. Wysocki try_to_freeze(); 3589ef87979cSStephen Hemminger continue; 3590ee74baa7SDavid S. Miller } 35911da177e4SLinus Torvalds 35921da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 35931da177e4SLinus Torvalds 3594ef87979cSStephen Hemminger if (likely(pkt_dev)) { 35951da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 35961da177e4SLinus Torvalds 3597ef87979cSStephen Hemminger if (need_resched()) 3598ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3599ef87979cSStephen Hemminger else 3600ef87979cSStephen Hemminger cpu_relax(); 3601ef87979cSStephen Hemminger } 3602ef87979cSStephen Hemminger 36031da177e4SLinus Torvalds if (t->control & T_STOP) { 36041da177e4SLinus Torvalds pktgen_stop(t); 36051da177e4SLinus Torvalds t->control &= ~(T_STOP); 36061da177e4SLinus Torvalds } 36071da177e4SLinus Torvalds 36081da177e4SLinus Torvalds if (t->control & T_RUN) { 36091da177e4SLinus Torvalds pktgen_run(t); 36101da177e4SLinus Torvalds t->control &= ~(T_RUN); 36111da177e4SLinus Torvalds } 36121da177e4SLinus Torvalds 361395ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36141da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 361595ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 361695ed63f7SArthur Kepner } 361795ed63f7SArthur Kepner 361895ed63f7SArthur Kepner if (t->control & T_REMDEV) { 361995ed63f7SArthur Kepner pktgen_rem_one_if(t); 36201da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36211da177e4SLinus Torvalds } 36221da177e4SLinus Torvalds 362309fe3ef4SAndrew Morton try_to_freeze(); 362409fe3ef4SAndrew Morton 3625ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 36261da177e4SLinus Torvalds } 36271da177e4SLinus Torvalds 3628f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36291da177e4SLinus Torvalds pktgen_stop(t); 36301da177e4SLinus Torvalds 3631f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36321da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36331da177e4SLinus Torvalds 3634f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36351da177e4SLinus Torvalds pktgen_rem_thread(t); 3636cdcdbe0bSLuiz Capitulino 3637ee74baa7SDavid S. Miller return 0; 36381da177e4SLinus Torvalds } 36391da177e4SLinus Torvalds 3640222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36413e984840SEric Dumazet const char *ifname, bool exact) 36421da177e4SLinus Torvalds { 3643c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36443e984840SEric Dumazet size_t len = strlen(ifname); 36451da177e4SLinus Torvalds 36463e984840SEric Dumazet if_lock(t); 3647c26a8016SLuiz Capitulino list_for_each_entry(p, &t->if_list, list) 36483e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36493e984840SEric Dumazet if (p->odevname[len]) { 36503e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36513e984840SEric Dumazet continue; 36523e984840SEric Dumazet } 3653c26a8016SLuiz Capitulino pkt_dev = p; 36541da177e4SLinus Torvalds break; 36551da177e4SLinus Torvalds } 36561da177e4SLinus Torvalds 36571da177e4SLinus Torvalds if_unlock(t); 3658f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36591da177e4SLinus Torvalds return pkt_dev; 36601da177e4SLinus Torvalds } 36611da177e4SLinus Torvalds 36621da177e4SLinus Torvalds /* 36631da177e4SLinus Torvalds * Adds a dev at front of if_list. 36641da177e4SLinus Torvalds */ 36651da177e4SLinus Torvalds 3666222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3667222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36681da177e4SLinus Torvalds { 36691da177e4SLinus Torvalds int rv = 0; 36701da177e4SLinus Torvalds 36711da177e4SLinus Torvalds if_lock(t); 36721da177e4SLinus Torvalds 36731da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3674f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 36751da177e4SLinus Torvalds rv = -EBUSY; 36761da177e4SLinus Torvalds goto out; 36771da177e4SLinus Torvalds } 3678c26a8016SLuiz Capitulino 3679c26a8016SLuiz Capitulino list_add(&pkt_dev->list, &t->if_list); 36801da177e4SLinus Torvalds pkt_dev->pg_thread = t; 36811da177e4SLinus Torvalds pkt_dev->running = 0; 36821da177e4SLinus Torvalds 36831da177e4SLinus Torvalds out: 36841da177e4SLinus Torvalds if_unlock(t); 36851da177e4SLinus Torvalds return rv; 36861da177e4SLinus Torvalds } 36871da177e4SLinus Torvalds 36881da177e4SLinus Torvalds /* Called under thread lock */ 36891da177e4SLinus Torvalds 36901da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 36911da177e4SLinus Torvalds { 36921da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 369339df232fSStephen Hemminger int err; 36943291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 36951da177e4SLinus Torvalds 36961da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 36971da177e4SLinus Torvalds 3698d50a6b56SStephen Hemminger pkt_dev = __pktgen_NN_threads(ifname, FIND); 3699d50a6b56SStephen Hemminger if (pkt_dev) { 3700f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3701d50a6b56SStephen Hemminger return -EBUSY; 3702d50a6b56SStephen Hemminger } 37031da177e4SLinus Torvalds 37043291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37051da177e4SLinus Torvalds if (!pkt_dev) 37061da177e4SLinus Torvalds return -ENOMEM; 37071da177e4SLinus Torvalds 3708593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 37093291b9dbSEric Dumazet pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 37103291b9dbSEric Dumazet node); 37111da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37121da177e4SLinus Torvalds kfree(pkt_dev); 37131da177e4SLinus Torvalds return -ENOMEM; 37141da177e4SLinus Torvalds } 37151da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); 37161da177e4SLinus Torvalds 371795ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37181da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 37191da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 37201da177e4SLinus Torvalds pkt_dev->nfrags = 0; 37211da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 3722fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37231da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37241da177e4SLinus Torvalds pkt_dev->sofar = 0; 37251da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37261da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37271da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37281da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 37291da177e4SLinus Torvalds 373034954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 373134954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 373234954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 373334954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 373434954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 373534954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 3736e99b99b4SRobert Olsson pkt_dev->node = -1; 373734954ddcSFrancesco Fondelli 373839df232fSStephen Hemminger err = pktgen_setup_dev(pkt_dev, ifname); 373939df232fSStephen Hemminger if (err) 374039df232fSStephen Hemminger goto out1; 37411da177e4SLinus Torvalds 37425efdccbcSDenis V. Lunev pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir, 37435efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 374439df232fSStephen Hemminger if (!pkt_dev->entry) { 3745f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3746d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 374739df232fSStephen Hemminger err = -EINVAL; 374839df232fSStephen Hemminger goto out2; 374939df232fSStephen Hemminger } 3750a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3751a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3752a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3753a553e4a6SJamal Hadi Salim #endif 375439df232fSStephen Hemminger 375539df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 375639df232fSStephen Hemminger out2: 375739df232fSStephen Hemminger dev_put(pkt_dev->odev); 375839df232fSStephen Hemminger out1: 3759a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3760a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3761a553e4a6SJamal Hadi Salim #endif 37621da177e4SLinus Torvalds vfree(pkt_dev->flows); 37631da177e4SLinus Torvalds kfree(pkt_dev); 376439df232fSStephen Hemminger return err; 37651da177e4SLinus Torvalds } 37661da177e4SLinus Torvalds 3767ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu) 37681da177e4SLinus Torvalds { 3769cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3770d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3771ee74baa7SDavid S. Miller struct task_struct *p; 37721da177e4SLinus Torvalds 37733291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 37743291b9dbSEric Dumazet cpu_to_node(cpu)); 37751da177e4SLinus Torvalds if (!t) { 3776f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 37771da177e4SLinus Torvalds return -ENOMEM; 37781da177e4SLinus Torvalds } 37791da177e4SLinus Torvalds 37801da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 37811da177e4SLinus Torvalds t->cpu = cpu; 37821da177e4SLinus Torvalds 3783ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3784ee74baa7SDavid S. Miller 3785ee74baa7SDavid S. Miller list_add_tail(&t->th_list, &pktgen_threads); 3786d3ede327SDenis V. Lunev init_completion(&t->start_done); 3787ee74baa7SDavid S. Miller 3788ee74baa7SDavid S. Miller p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); 3789ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3790f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3791ee74baa7SDavid S. Miller list_del(&t->th_list); 3792ee74baa7SDavid S. Miller kfree(t); 3793ee74baa7SDavid S. Miller return PTR_ERR(p); 3794ee74baa7SDavid S. Miller } 3795ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3796ee74baa7SDavid S. Miller t->tsk = p; 3797ee74baa7SDavid S. Miller 37985efdccbcSDenis V. Lunev pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir, 37995efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3800d50a6b56SStephen Hemminger if (!pe) { 3801f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3802ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3803ee74baa7SDavid S. Miller kthread_stop(p); 3804ee74baa7SDavid S. Miller list_del(&t->th_list); 38051da177e4SLinus Torvalds kfree(t); 38061da177e4SLinus Torvalds return -EINVAL; 38071da177e4SLinus Torvalds } 3808d50a6b56SStephen Hemminger 3809ee74baa7SDavid S. Miller wake_up_process(p); 3810d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38111da177e4SLinus Torvalds 38121da177e4SLinus Torvalds return 0; 38131da177e4SLinus Torvalds } 38141da177e4SLinus Torvalds 38151da177e4SLinus Torvalds /* 38161da177e4SLinus Torvalds * Removes a device from the thread if_list. 38171da177e4SLinus Torvalds */ 3818222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3819222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38201da177e4SLinus Torvalds { 3821c26a8016SLuiz Capitulino struct list_head *q, *n; 3822c26a8016SLuiz Capitulino struct pktgen_dev *p; 38231da177e4SLinus Torvalds 3824c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3825c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3826c26a8016SLuiz Capitulino if (p == pkt_dev) 3827c26a8016SLuiz Capitulino list_del(&p->list); 38281da177e4SLinus Torvalds } 38291da177e4SLinus Torvalds } 38301da177e4SLinus Torvalds 3831222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3832222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38331da177e4SLinus Torvalds { 38341da177e4SLinus Torvalds 3835f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38361da177e4SLinus Torvalds 38371da177e4SLinus Torvalds if (pkt_dev->running) { 3838f9467eaeSJoe Perches pr_warning("WARNING: trying to remove a running interface, stopping it now\n"); 38391da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38401da177e4SLinus Torvalds } 38411da177e4SLinus Torvalds 38421da177e4SLinus Torvalds /* Dis-associate from the interface */ 38431da177e4SLinus Torvalds 38441da177e4SLinus Torvalds if (pkt_dev->odev) { 38451da177e4SLinus Torvalds dev_put(pkt_dev->odev); 38461da177e4SLinus Torvalds pkt_dev->odev = NULL; 38471da177e4SLinus Torvalds } 38481da177e4SLinus Torvalds 38491da177e4SLinus Torvalds /* And update the thread if_list */ 38501da177e4SLinus Torvalds 38511da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 38521da177e4SLinus Torvalds 385339df232fSStephen Hemminger if (pkt_dev->entry) 385439df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 38551da177e4SLinus Torvalds 3856a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3857a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3858a553e4a6SJamal Hadi Salim #endif 38591da177e4SLinus Torvalds vfree(pkt_dev->flows); 38601da177e4SLinus Torvalds kfree(pkt_dev); 38611da177e4SLinus Torvalds return 0; 38621da177e4SLinus Torvalds } 38631da177e4SLinus Torvalds 38641da177e4SLinus Torvalds static int __init pg_init(void) 38651da177e4SLinus Torvalds { 38661da177e4SLinus Torvalds int cpu; 3867d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3868d50a6b56SStephen Hemminger 3869f9467eaeSJoe Perches pr_info("%s", version); 38701da177e4SLinus Torvalds 3871457c4cbcSEric W. Biederman pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); 3872d50a6b56SStephen Hemminger if (!pg_proc_dir) 3873d50a6b56SStephen Hemminger return -ENODEV; 38741da177e4SLinus Torvalds 387525296d59SWang Chen pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); 3876d50a6b56SStephen Hemminger if (pe == NULL) { 3877f9467eaeSJoe Perches pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); 3878457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 38791da177e4SLinus Torvalds return -EINVAL; 38801da177e4SLinus Torvalds } 38811da177e4SLinus Torvalds 38821da177e4SLinus Torvalds /* Register us to receive netdevice events */ 38831da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 38841da177e4SLinus Torvalds 3885670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 38868024bb24SLuiz Capitulino int err; 38871da177e4SLinus Torvalds 3888ee74baa7SDavid S. Miller err = pktgen_create_thread(cpu); 38898024bb24SLuiz Capitulino if (err) 3890f9467eaeSJoe Perches pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n", 3891f9467eaeSJoe Perches cpu, err); 38921da177e4SLinus Torvalds } 38938024bb24SLuiz Capitulino 38948024bb24SLuiz Capitulino if (list_empty(&pktgen_threads)) { 3895f9467eaeSJoe Perches pr_err("ERROR: Initialization failed for all threads\n"); 38968024bb24SLuiz Capitulino unregister_netdevice_notifier(&pktgen_notifier_block); 38978024bb24SLuiz Capitulino remove_proc_entry(PGCTRL, pg_proc_dir); 3898457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 38998024bb24SLuiz Capitulino return -ENODEV; 39008024bb24SLuiz Capitulino } 39018024bb24SLuiz Capitulino 39021da177e4SLinus Torvalds return 0; 39031da177e4SLinus Torvalds } 39041da177e4SLinus Torvalds 39051da177e4SLinus Torvalds static void __exit pg_cleanup(void) 39061da177e4SLinus Torvalds { 3907cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3908cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 39091da177e4SLinus Torvalds 39101da177e4SLinus Torvalds /* Stop all interfaces & threads */ 39111da177e4SLinus Torvalds 3912cdcdbe0bSLuiz Capitulino list_for_each_safe(q, n, &pktgen_threads) { 3913cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3914ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3915ee74baa7SDavid S. Miller kfree(t); 39161da177e4SLinus Torvalds } 39171da177e4SLinus Torvalds 39181da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 39191da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 39201da177e4SLinus Torvalds 39211da177e4SLinus Torvalds /* Clean up proc file system */ 3922d50a6b56SStephen Hemminger remove_proc_entry(PGCTRL, pg_proc_dir); 3923457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39241da177e4SLinus Torvalds } 39251da177e4SLinus Torvalds 39261da177e4SLinus Torvalds module_init(pg_init); 39271da177e4SLinus Torvalds module_exit(pg_cleanup); 39281da177e4SLinus Torvalds 3929c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 39301da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 39311da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3932c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 39331da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3934c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 39351da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3936c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 39371da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3938c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 39391da177e4SLinus Torvalds module_param(debug, int, 0); 3940c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3941