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; 381*9e50e3acSJohn Fastabend __u32 skb_priority; /* skb priority field */ 382e99b99b4SRobert Olsson int node; /* Memory node */ 38345b270f8SRobert Olsson 384a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 385a553e4a6SJamal Hadi Salim __u8 ipsmode; /* IPSEC mode (config) */ 386a553e4a6SJamal Hadi Salim __u8 ipsproto; /* IPSEC type (config) */ 387a553e4a6SJamal Hadi Salim #endif 38839df232fSStephen Hemminger char result[512]; 3891da177e4SLinus Torvalds }; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds struct pktgen_hdr { 392252e3346SAl Viro __be32 pgh_magic; 393252e3346SAl Viro __be32 seq_num; 394252e3346SAl Viro __be32 tv_sec; 395252e3346SAl Viro __be32 tv_usec; 3961da177e4SLinus Torvalds }; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds struct pktgen_thread { 39963adc6fbSStephen Hemminger spinlock_t if_lock; /* for list of devices */ 400c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 401cdcdbe0bSLuiz Capitulino struct list_head th_list; 402ee74baa7SDavid S. Miller struct task_struct *tsk; 4031da177e4SLinus Torvalds char result[512]; 4041da177e4SLinus Torvalds 40563adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 40663adc6fbSStephen Hemminger stop ifs etc. */ 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds u32 control; 4091da177e4SLinus Torvalds int cpu; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds wait_queue_head_t queue; 412d3ede327SDenis V. Lunev struct completion start_done; 4131da177e4SLinus Torvalds }; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds #define REMOVE 1 4161da177e4SLinus Torvalds #define FIND 0 4171da177e4SLinus Torvalds 418fd29cf72SStephen Hemminger static inline ktime_t ktime_now(void) 4191da177e4SLinus Torvalds { 420fd29cf72SStephen Hemminger struct timespec ts; 421fd29cf72SStephen Hemminger ktime_get_ts(&ts); 422fd29cf72SStephen Hemminger 423fd29cf72SStephen Hemminger return timespec_to_ktime(ts); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 426fd29cf72SStephen Hemminger /* This works even if 32 bit because of careful byte order choice */ 427fd29cf72SStephen Hemminger static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2) 4281da177e4SLinus Torvalds { 429fd29cf72SStephen Hemminger return cmp1.tv64 < cmp2.tv64; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds 432c3d2f52dSStephen Hemminger static const char version[] = 433f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 434f9467eaeSJoe Perches "Version: " VERSION "\n"; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4371da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 438222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4393e984840SEric Dumazet const char *ifname, bool exact); 4401da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4411da177e4SLinus Torvalds static void pktgen_run_all_threads(void); 442eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void); 4431da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void); 4443bda06a3SStephen Hemminger 4451da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4461da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 44739df232fSStephen Hemminger 4481da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]); 4491da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s, const char ip[16]); 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds /* Module parameters, defaults. */ 45265c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 45365c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 45465c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 45565c5b786SStephen Hemminger static int debug __read_mostly; 4561da177e4SLinus Torvalds 457222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 458cdcdbe0bSLuiz Capitulino static LIST_HEAD(pktgen_threads); 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4611da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4621da177e4SLinus Torvalds }; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds /* 4651da177e4SLinus Torvalds * /proc handling functions 4661da177e4SLinus Torvalds * 4671da177e4SLinus Torvalds */ 4681da177e4SLinus Torvalds 469d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 470d50a6b56SStephen Hemminger { 471c3d2f52dSStephen Hemminger seq_puts(seq, version); 472d50a6b56SStephen Hemminger return 0; 473d50a6b56SStephen Hemminger } 4741da177e4SLinus Torvalds 475d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4761da177e4SLinus Torvalds size_t count, loff_t *ppos) 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds int err = 0; 479d50a6b56SStephen Hemminger char data[128]; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) { 4821da177e4SLinus Torvalds err = -EPERM; 4831da177e4SLinus Torvalds goto out; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 486d50a6b56SStephen Hemminger if (count > sizeof(data)) 487d50a6b56SStephen Hemminger count = sizeof(data); 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds if (copy_from_user(data, buf, count)) { 4901da177e4SLinus Torvalds err = -EFAULT; 491d50a6b56SStephen Hemminger goto out; 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds data[count - 1] = 0; /* Make string */ 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds if (!strcmp(data, "stop")) 4961da177e4SLinus Torvalds pktgen_stop_all_threads_ifs(); 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds else if (!strcmp(data, "start")) 4991da177e4SLinus Torvalds pktgen_run_all_threads(); 5001da177e4SLinus Torvalds 501eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 502eb37b41cSJesse Brandeburg pktgen_reset_all_threads(); 503eb37b41cSJesse Brandeburg 5041da177e4SLinus Torvalds else 505f9467eaeSJoe Perches pr_warning("Unknown command: %s\n", data); 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds err = count; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds out: 5101da177e4SLinus Torvalds return err; 5111da177e4SLinus Torvalds } 5121da177e4SLinus Torvalds 513d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5141da177e4SLinus Torvalds { 515d50a6b56SStephen Hemminger return single_open(file, pgctrl_show, PDE(inode)->data); 516d50a6b56SStephen Hemminger } 517d50a6b56SStephen Hemminger 5189a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 519d50a6b56SStephen Hemminger .owner = THIS_MODULE, 520d50a6b56SStephen Hemminger .open = pgctrl_open, 521d50a6b56SStephen Hemminger .read = seq_read, 522d50a6b56SStephen Hemminger .llseek = seq_lseek, 523d50a6b56SStephen Hemminger .write = pgctrl_write, 524d50a6b56SStephen Hemminger .release = single_release, 525d50a6b56SStephen Hemminger }; 526d50a6b56SStephen Hemminger 527d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 528d50a6b56SStephen Hemminger { 529648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 530fd29cf72SStephen Hemminger ktime_t stopped; 531fd29cf72SStephen Hemminger u64 idle; 5321da177e4SLinus Torvalds 533222f1806SLuiz Capitulino seq_printf(seq, 534222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 535222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 536222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5371da177e4SLinus Torvalds 538222f1806SLuiz Capitulino seq_printf(seq, 539fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 540fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 541593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5421da177e4SLinus Torvalds 543222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 544222f1806SLuiz Capitulino pkt_dev->lflow); 5451da177e4SLinus Torvalds 54645b270f8SRobert Olsson seq_printf(seq, 54745b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 54845b270f8SRobert Olsson pkt_dev->queue_map_min, 54945b270f8SRobert Olsson pkt_dev->queue_map_max); 55045b270f8SRobert Olsson 551*9e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 552*9e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 553*9e50e3acSJohn Fastabend pkt_dev->skb_priority); 554*9e50e3acSJohn Fastabend 5551da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 5561da177e4SLinus Torvalds char b1[128], b2[128], b3[128]; 5571da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); 5581da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); 5591da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); 560222f1806SLuiz Capitulino seq_printf(seq, 561222f1806SLuiz Capitulino " saddr: %s min_saddr: %s max_saddr: %s\n", b1, 562222f1806SLuiz Capitulino b2, b3); 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); 5651da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); 5661da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); 567222f1806SLuiz Capitulino seq_printf(seq, 568222f1806SLuiz Capitulino " daddr: %s min_daddr: %s max_daddr: %s\n", b1, 569222f1806SLuiz Capitulino b2, b3); 5701da177e4SLinus Torvalds 57163adc6fbSStephen Hemminger } else { 572222f1806SLuiz Capitulino seq_printf(seq, 57363adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 57463adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 57563adc6fbSStephen Hemminger seq_printf(seq, 57663adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 57763adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 57863adc6fbSStephen Hemminger } 5791da177e4SLinus Torvalds 580d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5811da177e4SLinus Torvalds 582e174961cSJohannes Berg seq_printf(seq, "%pM ", 583e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 584e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5851da177e4SLinus Torvalds 586d50a6b56SStephen Hemminger seq_printf(seq, "dst_mac: "); 587e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5881da177e4SLinus Torvalds 589222f1806SLuiz Capitulino seq_printf(seq, 59063adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 59163adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 592222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 593222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 5941da177e4SLinus Torvalds 595222f1806SLuiz Capitulino seq_printf(seq, 596ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 5971da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 5981da177e4SLinus Torvalds 599ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 600ca6549afSSteven Whitehouse unsigned i; 601ca6549afSSteven Whitehouse seq_printf(seq, " mpls: "); 602ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 603ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 604ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 605ca6549afSSteven Whitehouse } 606ca6549afSSteven Whitehouse 60763adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 60834954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 60963adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 61063adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 61134954ddcSFrancesco Fondelli 61263adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 61334954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 61463adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 61563adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 61634954ddcSFrancesco Fondelli 61763adc6fbSStephen Hemminger if (pkt_dev->tos) 6181ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6191ca7768cSFrancesco Fondelli 62063adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6211ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6221ca7768cSFrancesco Fondelli 623e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 624e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 625e99b99b4SRobert Olsson 626ca6549afSSteven Whitehouse seq_printf(seq, " Flags: "); 627ca6549afSSteven Whitehouse 6281da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 629d50a6b56SStephen Hemminger seq_printf(seq, "IPV6 "); 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 632d50a6b56SStephen Hemminger seq_printf(seq, "IPSRC_RND "); 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 635d50a6b56SStephen Hemminger seq_printf(seq, "IPDST_RND "); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 638d50a6b56SStephen Hemminger seq_printf(seq, "TXSIZE_RND "); 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 641d50a6b56SStephen Hemminger seq_printf(seq, "UDPSRC_RND "); 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 644d50a6b56SStephen Hemminger seq_printf(seq, "UDPDST_RND "); 6451da177e4SLinus Torvalds 646ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 647ca6549afSSteven Whitehouse seq_printf(seq, "MPLS_RND "); 648ca6549afSSteven Whitehouse 64945b270f8SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_RND) 65045b270f8SRobert Olsson seq_printf(seq, "QUEUE_MAP_RND "); 65145b270f8SRobert Olsson 652e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 653e6fce5b9SRobert Olsson seq_printf(seq, "QUEUE_MAP_CPU "); 654e6fce5b9SRobert Olsson 655007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 656007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 657007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/ 658007a531bSJamal Hadi Salim else 659007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_RND "); 660007a531bSJamal Hadi Salim } 661007a531bSJamal Hadi Salim 662a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 663a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 664a553e4a6SJamal Hadi Salim seq_printf(seq, "IPSEC "); 665a553e4a6SJamal Hadi Salim #endif 666a553e4a6SJamal Hadi Salim 6671da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 668d50a6b56SStephen Hemminger seq_printf(seq, "MACSRC_RND "); 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 671d50a6b56SStephen Hemminger seq_printf(seq, "MACDST_RND "); 6721da177e4SLinus Torvalds 67334954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 67434954ddcSFrancesco Fondelli seq_printf(seq, "VID_RND "); 67534954ddcSFrancesco Fondelli 67634954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 67734954ddcSFrancesco Fondelli seq_printf(seq, "SVID_RND "); 67834954ddcSFrancesco Fondelli 679e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) 680e99b99b4SRobert Olsson seq_printf(seq, "NODE_ALLOC "); 681e99b99b4SRobert Olsson 682d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6831da177e4SLinus Torvalds 684fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 685fd29cf72SStephen Hemminger stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at; 686fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 687fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6881da177e4SLinus Torvalds 689222f1806SLuiz Capitulino seq_printf(seq, 690fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6911da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 692fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 693fd29cf72SStephen Hemminger 694fd29cf72SStephen Hemminger seq_printf(seq, 695fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 696fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 697fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 698fd29cf72SStephen Hemminger (unsigned long long) idle); 6991da177e4SLinus Torvalds 700222f1806SLuiz Capitulino seq_printf(seq, 701222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 702d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 703d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 7061da177e4SLinus Torvalds char b1[128], b2[128]; 7071da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); 7081da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); 709d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); 710222f1806SLuiz Capitulino } else 711d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", 7121da177e4SLinus Torvalds pkt_dev->cur_saddr, pkt_dev->cur_daddr); 7131da177e4SLinus Torvalds 714d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7151da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7161da177e4SLinus Torvalds 71745b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 71845b270f8SRobert Olsson 719d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds if (pkt_dev->result[0]) 722d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7231da177e4SLinus Torvalds else 724d50a6b56SStephen Hemminger seq_printf(seq, "Result: Idle\n"); 7251da177e4SLinus Torvalds 726d50a6b56SStephen Hemminger return 0; 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 729ca6549afSSteven Whitehouse 73063adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 73163adc6fbSStephen Hemminger __u32 *num) 732ca6549afSSteven Whitehouse { 733ca6549afSSteven Whitehouse int i = 0; 734ca6549afSSteven Whitehouse *num = 0; 735ca6549afSSteven Whitehouse 7361ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 73782fd5b5dSAndy Shevchenko int value; 738ca6549afSSteven Whitehouse char c; 739ca6549afSSteven Whitehouse *num <<= 4; 740ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 741ca6549afSSteven Whitehouse return -EFAULT; 74282fd5b5dSAndy Shevchenko value = hex_to_bin(c); 74382fd5b5dSAndy Shevchenko if (value >= 0) 74482fd5b5dSAndy Shevchenko *num |= value; 745ca6549afSSteven Whitehouse else 746ca6549afSSteven Whitehouse break; 747ca6549afSSteven Whitehouse } 748ca6549afSSteven Whitehouse return i; 749ca6549afSSteven Whitehouse } 750ca6549afSSteven Whitehouse 751222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 752222f1806SLuiz Capitulino unsigned int maxlen) 7531da177e4SLinus Torvalds { 7541da177e4SLinus Torvalds int i; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7571da177e4SLinus Torvalds char c; 7581da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7591da177e4SLinus Torvalds return -EFAULT; 7601da177e4SLinus Torvalds switch (c) { 7611da177e4SLinus Torvalds case '\"': 7621da177e4SLinus Torvalds case '\n': 7631da177e4SLinus Torvalds case '\r': 7641da177e4SLinus Torvalds case '\t': 7651da177e4SLinus Torvalds case ' ': 7661da177e4SLinus Torvalds case '=': 7671da177e4SLinus Torvalds break; 7681da177e4SLinus Torvalds default: 7691da177e4SLinus Torvalds goto done; 7703ff50b79SStephen Hemminger } 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds done: 7731da177e4SLinus Torvalds return i; 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 776222f1806SLuiz Capitulino static unsigned long num_arg(const char __user * user_buffer, 777222f1806SLuiz Capitulino unsigned long maxlen, unsigned long *num) 7781da177e4SLinus Torvalds { 779d6182223SPaul Gortmaker int i; 7801da177e4SLinus Torvalds *num = 0; 7811da177e4SLinus Torvalds 782d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7831da177e4SLinus Torvalds char c; 7841da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7851da177e4SLinus Torvalds return -EFAULT; 7861da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 7871da177e4SLinus Torvalds *num *= 10; 7881da177e4SLinus Torvalds *num += c - '0'; 7891da177e4SLinus Torvalds } else 7901da177e4SLinus Torvalds break; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds return i; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 7961da177e4SLinus Torvalds { 797d6182223SPaul Gortmaker int i; 7981da177e4SLinus Torvalds 799d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8001da177e4SLinus Torvalds char c; 8011da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8021da177e4SLinus Torvalds return -EFAULT; 8031da177e4SLinus Torvalds switch (c) { 8041da177e4SLinus Torvalds case '\"': 8051da177e4SLinus Torvalds case '\n': 8061da177e4SLinus Torvalds case '\r': 8071da177e4SLinus Torvalds case '\t': 8081da177e4SLinus Torvalds case ' ': 8091da177e4SLinus Torvalds goto done_str; 8101da177e4SLinus Torvalds break; 8111da177e4SLinus Torvalds default: 8121da177e4SLinus Torvalds break; 8133ff50b79SStephen Hemminger } 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds done_str: 8161da177e4SLinus Torvalds return i; 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 819ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 820ca6549afSSteven Whitehouse { 821ca6549afSSteven Whitehouse unsigned n = 0; 822ca6549afSSteven Whitehouse char c; 823ca6549afSSteven Whitehouse ssize_t i = 0; 824ca6549afSSteven Whitehouse int len; 825ca6549afSSteven Whitehouse 826ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 827ca6549afSSteven Whitehouse do { 828ca6549afSSteven Whitehouse __u32 tmp; 8291ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 830ca6549afSSteven Whitehouse if (len <= 0) 831ca6549afSSteven Whitehouse return len; 832ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 833ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 834ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 835ca6549afSSteven Whitehouse i += len; 836ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 837ca6549afSSteven Whitehouse return -EFAULT; 838ca6549afSSteven Whitehouse i++; 839ca6549afSSteven Whitehouse n++; 840ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 841ca6549afSSteven Whitehouse return -E2BIG; 842ca6549afSSteven Whitehouse } while (c == ','); 843ca6549afSSteven Whitehouse 844ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 845ca6549afSSteven Whitehouse return i; 846ca6549afSSteven Whitehouse } 847ca6549afSSteven Whitehouse 848222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 849222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 850222f1806SLuiz Capitulino loff_t * offset) 8511da177e4SLinus Torvalds { 8528a994a71SJoe Perches struct seq_file *seq = file->private_data; 853d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 854d6182223SPaul Gortmaker int i, max, len; 8551da177e4SLinus Torvalds char name[16], valstr[32]; 8561da177e4SLinus Torvalds unsigned long value = 0; 8571da177e4SLinus Torvalds char *pg_result = NULL; 8581da177e4SLinus Torvalds int tmp = 0; 8591da177e4SLinus Torvalds char buf[128]; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds if (count < 1) { 864f9467eaeSJoe Perches pr_warning("wrong command format\n"); 8651da177e4SLinus Torvalds return -EINVAL; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 868d6182223SPaul Gortmaker max = count; 869d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8701da177e4SLinus Torvalds if (tmp < 0) { 871f9467eaeSJoe Perches pr_warning("illegal format\n"); 8721da177e4SLinus Torvalds return tmp; 8731da177e4SLinus Torvalds } 874d6182223SPaul Gortmaker i = tmp; 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds /* Read variable name */ 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 87963adc6fbSStephen Hemminger if (len < 0) 880222f1806SLuiz Capitulino return len; 88163adc6fbSStephen Hemminger 8821da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 8831da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 8841da177e4SLinus Torvalds return -EFAULT; 8851da177e4SLinus Torvalds i += len; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds max = count - i; 8881da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 8891da177e4SLinus Torvalds if (len < 0) 8901da177e4SLinus Torvalds return len; 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds i += len; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds if (debug) { 89586c2c0a8SDmitry Torokhov size_t copy = min_t(size_t, count, 1023); 896448d7b5dSNelson Elhage char tb[copy + 1]; 897448d7b5dSNelson Elhage if (copy_from_user(tb, user_buffer, copy)) 8981da177e4SLinus Torvalds return -EFAULT; 899448d7b5dSNelson Elhage tb[copy] = 0; 90025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, 901d50a6b56SStephen Hemminger (unsigned long)count, tb); 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9051da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 90663adc6fbSStephen Hemminger if (len < 0) 907222f1806SLuiz Capitulino return len; 90863adc6fbSStephen Hemminger 9091da177e4SLinus Torvalds i += len; 9101da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9111da177e4SLinus Torvalds value = 14 + 20 + 8; 9121da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9131da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9141da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9151da177e4SLinus Torvalds } 916222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 917222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9181da177e4SLinus Torvalds return count; 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9221da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 92363adc6fbSStephen Hemminger if (len < 0) 924222f1806SLuiz Capitulino return len; 92563adc6fbSStephen Hemminger 9261da177e4SLinus Torvalds i += len; 9271da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9281da177e4SLinus Torvalds value = 14 + 20 + 8; 9291da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9301da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9311da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9321da177e4SLinus Torvalds } 933222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 934222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9351da177e4SLinus Torvalds return count; 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds /* Shortcut for min = max */ 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9411da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 94263adc6fbSStephen Hemminger if (len < 0) 943222f1806SLuiz Capitulino return len; 94463adc6fbSStephen Hemminger 9451da177e4SLinus Torvalds i += len; 9461da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9471da177e4SLinus Torvalds value = 14 + 20 + 8; 9481da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9491da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9501da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9511da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9541da177e4SLinus Torvalds return count; 9551da177e4SLinus Torvalds } 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9581da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 95963adc6fbSStephen Hemminger if (len < 0) 960222f1806SLuiz Capitulino return len; 96163adc6fbSStephen Hemminger 9621da177e4SLinus Torvalds i += len; 9631da177e4SLinus Torvalds debug = value; 9641da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9651da177e4SLinus Torvalds return count; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9691da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97063adc6fbSStephen Hemminger if (len < 0) 971222f1806SLuiz Capitulino return len; 97263adc6fbSStephen Hemminger 9731da177e4SLinus Torvalds i += len; 9741da177e4SLinus Torvalds pkt_dev->nfrags = value; 9751da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 9761da177e4SLinus Torvalds return count; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9791da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 98063adc6fbSStephen Hemminger if (len < 0) 981222f1806SLuiz Capitulino return len; 98263adc6fbSStephen Hemminger 9831da177e4SLinus Torvalds i += len; 984fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 985fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 986fd29cf72SStephen Hemminger else 9879240d715SEric Dumazet pkt_dev->delay = (u64)value; 988fd29cf72SStephen Hemminger 989fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 990fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9911da177e4SLinus Torvalds return count; 9921da177e4SLinus Torvalds } 99343d28b65SDaniel Turull if (!strcmp(name, "rate")) { 99443d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 99543d28b65SDaniel Turull if (len < 0) 99643d28b65SDaniel Turull return len; 99743d28b65SDaniel Turull 99843d28b65SDaniel Turull i += len; 99943d28b65SDaniel Turull if (!value) 100043d28b65SDaniel Turull return len; 100143d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 100243d28b65SDaniel Turull if (debug) 1003f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 100443d28b65SDaniel Turull 100543d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 100643d28b65SDaniel Turull return count; 100743d28b65SDaniel Turull } 100843d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 100943d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 101043d28b65SDaniel Turull if (len < 0) 101143d28b65SDaniel Turull return len; 101243d28b65SDaniel Turull 101343d28b65SDaniel Turull i += len; 101443d28b65SDaniel Turull if (!value) 101543d28b65SDaniel Turull return len; 101643d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 101743d28b65SDaniel Turull if (debug) 1018f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 101943d28b65SDaniel Turull 102043d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 102143d28b65SDaniel Turull return count; 102243d28b65SDaniel Turull } 10231da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10241da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 102563adc6fbSStephen Hemminger if (len < 0) 1026222f1806SLuiz Capitulino return len; 102763adc6fbSStephen Hemminger 10281da177e4SLinus Torvalds i += len; 10291da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10301da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10311da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10321da177e4SLinus Torvalds } 10331da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10341da177e4SLinus Torvalds return count; 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10371da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 103863adc6fbSStephen Hemminger if (len < 0) 1039222f1806SLuiz Capitulino return len; 104063adc6fbSStephen Hemminger 10411da177e4SLinus Torvalds i += len; 10421da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10431da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10441da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10471da177e4SLinus Torvalds return count; 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10501da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105163adc6fbSStephen Hemminger if (len < 0) 1052222f1806SLuiz Capitulino return len; 105363adc6fbSStephen Hemminger 10541da177e4SLinus Torvalds i += len; 10551da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10561da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10571da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10601da177e4SLinus Torvalds return count; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10631da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 106463adc6fbSStephen Hemminger if (len < 0) 1065222f1806SLuiz Capitulino return len; 106663adc6fbSStephen Hemminger 10671da177e4SLinus Torvalds i += len; 10681da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10691da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10701da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10731da177e4SLinus Torvalds return count; 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10761da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107763adc6fbSStephen Hemminger if (len < 0) 1078222f1806SLuiz Capitulino return len; 107963adc6fbSStephen Hemminger 10801da177e4SLinus Torvalds i += len; 10811da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10841da177e4SLinus Torvalds return count; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10871da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 108863adc6fbSStephen Hemminger if (len < 0) 1089222f1806SLuiz Capitulino return len; 109063adc6fbSStephen Hemminger 10911da177e4SLinus Torvalds i += len; 10921da177e4SLinus Torvalds pkt_dev->count = value; 10931da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 10941da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 10951da177e4SLinus Torvalds return count; 10961da177e4SLinus Torvalds } 10971da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 10981da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109963adc6fbSStephen Hemminger if (len < 0) 1100222f1806SLuiz Capitulino return len; 110163adc6fbSStephen Hemminger 11021da177e4SLinus Torvalds i += len; 11031da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11041da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11051da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11061da177e4SLinus Torvalds } 1107222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1108222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11091da177e4SLinus Torvalds return count; 11101da177e4SLinus Torvalds } 11111da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11121da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 111363adc6fbSStephen Hemminger if (len < 0) 1114222f1806SLuiz Capitulino return len; 111563adc6fbSStephen Hemminger 11161da177e4SLinus Torvalds i += len; 11171da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11181da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11191da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11201da177e4SLinus Torvalds } 1121222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1122222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11231da177e4SLinus Torvalds return count; 11241da177e4SLinus Torvalds } 1125e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1126e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1127e99b99b4SRobert Olsson if (len < 0) 1128e99b99b4SRobert Olsson return len; 1129e99b99b4SRobert Olsson 1130e99b99b4SRobert Olsson i += len; 1131e99b99b4SRobert Olsson 1132e99b99b4SRobert Olsson if (node_possible(value)) { 1133e99b99b4SRobert Olsson pkt_dev->node = value; 1134e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 1135e99b99b4SRobert Olsson } 1136e99b99b4SRobert Olsson else 1137e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1138e99b99b4SRobert Olsson return count; 1139e99b99b4SRobert Olsson } 11401da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11411da177e4SLinus Torvalds char f[32]; 11421da177e4SLinus Torvalds memset(f, 0, 32); 11431da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 114463adc6fbSStephen Hemminger if (len < 0) 1145222f1806SLuiz Capitulino return len; 114663adc6fbSStephen Hemminger 11471da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11481da177e4SLinus Torvalds return -EFAULT; 11491da177e4SLinus Torvalds i += len; 11501da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11511da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11521da177e4SLinus Torvalds 11531da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11541da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11571da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11601da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11631da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11661da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11691da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11721da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11751da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11781da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11811da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11841da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11871da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11901da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11911da177e4SLinus Torvalds 1192ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1193ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1194ca6549afSSteven Whitehouse 1195ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1196ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1197ca6549afSSteven Whitehouse 119834954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 119934954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 120034954ddcSFrancesco Fondelli 120134954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 120234954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 120334954ddcSFrancesco Fondelli 120434954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 120534954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 120634954ddcSFrancesco Fondelli 120734954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 120834954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 120934954ddcSFrancesco Fondelli 1210007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1211007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1212007a531bSJamal Hadi Salim 121345b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 121445b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 121545b270f8SRobert Olsson 121645b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 121745b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1218e6fce5b9SRobert Olsson 1219e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1220e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1221e6fce5b9SRobert Olsson 1222e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1223e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1224a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1225a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1226a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1227a553e4a6SJamal Hadi Salim #endif 1228a553e4a6SJamal Hadi Salim 12291ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12301ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12311ca7768cSFrancesco Fondelli 1232e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1233e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1234e99b99b4SRobert Olsson 1235e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1236e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1237e99b99b4SRobert Olsson 12381da177e4SLinus Torvalds else { 1239222f1806SLuiz Capitulino sprintf(pg_result, 1240222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12411da177e4SLinus Torvalds f, 12421ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 1243e99b99b4SRobert Olsson "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n"); 12441da177e4SLinus Torvalds return count; 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12471da177e4SLinus Torvalds return count; 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12501da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 125163adc6fbSStephen Hemminger if (len < 0) 1252222f1806SLuiz Capitulino return len; 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12551da177e4SLinus Torvalds return -EFAULT; 12561da177e4SLinus Torvalds buf[len] = 0; 12571da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12581da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12591da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12601da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12611da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12621da177e4SLinus Torvalds } 12631da177e4SLinus Torvalds if (debug) 126425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_min set to: %s\n", 1265222f1806SLuiz Capitulino pkt_dev->dst_min); 12661da177e4SLinus Torvalds i += len; 12671da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12681da177e4SLinus Torvalds return count; 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12711da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 127263adc6fbSStephen Hemminger if (len < 0) 1273222f1806SLuiz Capitulino return len; 127463adc6fbSStephen Hemminger 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12771da177e4SLinus Torvalds return -EFAULT; 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds buf[len] = 0; 12801da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12811da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12821da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 12831da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12841da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds if (debug) 128725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_max set to: %s\n", 1288222f1806SLuiz Capitulino pkt_dev->dst_max); 12891da177e4SLinus Torvalds i += len; 12901da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12911da177e4SLinus Torvalds return count; 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12941da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1295222f1806SLuiz Capitulino if (len < 0) 1296222f1806SLuiz Capitulino return len; 12971da177e4SLinus Torvalds 12981da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13011da177e4SLinus Torvalds return -EFAULT; 13021da177e4SLinus Torvalds buf[len] = 0; 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13051da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13061da177e4SLinus Torvalds 13071da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds if (debug) 131025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf); 13111da177e4SLinus Torvalds 13121da177e4SLinus Torvalds i += len; 13131da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13141da177e4SLinus Torvalds return count; 13151da177e4SLinus Torvalds } 13161da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13171da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1318222f1806SLuiz Capitulino if (len < 0) 1319222f1806SLuiz Capitulino return len; 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13241da177e4SLinus Torvalds return -EFAULT; 13251da177e4SLinus Torvalds buf[len] = 0; 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13281da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13291da177e4SLinus Torvalds 1330222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev->cur_in6_daddr, 1331222f1806SLuiz Capitulino &pkt_dev->min_in6_daddr); 13321da177e4SLinus Torvalds if (debug) 133325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf); 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds i += len; 13361da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13371da177e4SLinus Torvalds return count; 13381da177e4SLinus Torvalds } 13391da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13401da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1341222f1806SLuiz Capitulino if (len < 0) 1342222f1806SLuiz Capitulino return len; 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13451da177e4SLinus Torvalds 13461da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13471da177e4SLinus Torvalds return -EFAULT; 13481da177e4SLinus Torvalds buf[len] = 0; 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13511da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13521da177e4SLinus Torvalds 13531da177e4SLinus Torvalds if (debug) 135425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); 13551da177e4SLinus Torvalds 13561da177e4SLinus Torvalds i += len; 13571da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13581da177e4SLinus Torvalds return count; 13591da177e4SLinus Torvalds } 13601da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13611da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1362222f1806SLuiz Capitulino if (len < 0) 1363222f1806SLuiz Capitulino return len; 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13681da177e4SLinus Torvalds return -EFAULT; 13691da177e4SLinus Torvalds buf[len] = 0; 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13721da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 13751da177e4SLinus Torvalds 13761da177e4SLinus Torvalds if (debug) 137725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf); 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds i += len; 13801da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13811da177e4SLinus Torvalds return count; 13821da177e4SLinus Torvalds } 13831da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13841da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 138563adc6fbSStephen Hemminger if (len < 0) 1386222f1806SLuiz Capitulino return len; 138763adc6fbSStephen Hemminger 13881da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13891da177e4SLinus Torvalds return -EFAULT; 13901da177e4SLinus Torvalds buf[len] = 0; 13911da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13921da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13931da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 13941da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13951da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13961da177e4SLinus Torvalds } 13971da177e4SLinus Torvalds if (debug) 139825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_min set to: %s\n", 1399222f1806SLuiz Capitulino pkt_dev->src_min); 14001da177e4SLinus Torvalds i += len; 14011da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 14021da177e4SLinus Torvalds return count; 14031da177e4SLinus Torvalds } 14041da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 14051da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 140663adc6fbSStephen Hemminger if (len < 0) 1407222f1806SLuiz Capitulino return len; 140863adc6fbSStephen Hemminger 14091da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14101da177e4SLinus Torvalds return -EFAULT; 14111da177e4SLinus Torvalds buf[len] = 0; 14121da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14131da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14141da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14151da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14161da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds if (debug) 141925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_max set to: %s\n", 1420222f1806SLuiz Capitulino pkt_dev->src_max); 14211da177e4SLinus Torvalds i += len; 14221da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14231da177e4SLinus Torvalds return count; 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14261da177e4SLinus Torvalds char *v = valstr; 1427f404e9a6SKris Katterjohn unsigned char old_dmac[ETH_ALEN]; 14281da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1429f404e9a6SKris Katterjohn memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); 14301da177e4SLinus Torvalds 14311da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 143263adc6fbSStephen Hemminger if (len < 0) 1433222f1806SLuiz Capitulino return len; 143463adc6fbSStephen Hemminger 14351da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14361da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14371da177e4SLinus Torvalds return -EFAULT; 14381da177e4SLinus Torvalds i += len; 14391da177e4SLinus Torvalds 14401da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { 1441451e07a2SAndy Shevchenko int value; 1442451e07a2SAndy Shevchenko 1443451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1444451e07a2SAndy Shevchenko if (value >= 0) 1445451e07a2SAndy Shevchenko *m = *m * 16 + value; 1446451e07a2SAndy Shevchenko 14471da177e4SLinus Torvalds if (*v == ':') { 14481da177e4SLinus Torvalds m++; 14491da177e4SLinus Torvalds *m = 0; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds } 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds /* Set up Dest MAC */ 1454f404e9a6SKris Katterjohn if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) 1455f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 14561da177e4SLinus Torvalds 14571da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 14581da177e4SLinus Torvalds return count; 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14611da177e4SLinus Torvalds char *v = valstr; 1462ce5d0b47SAdit Ranadive unsigned char old_smac[ETH_ALEN]; 14631da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 14641da177e4SLinus Torvalds 1465ce5d0b47SAdit Ranadive memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); 1466ce5d0b47SAdit Ranadive 14671da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 146863adc6fbSStephen Hemminger if (len < 0) 1469222f1806SLuiz Capitulino return len; 147063adc6fbSStephen Hemminger 14711da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14721da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14731da177e4SLinus Torvalds return -EFAULT; 14741da177e4SLinus Torvalds i += len; 14751da177e4SLinus Torvalds 14761da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { 1477451e07a2SAndy Shevchenko int value; 1478451e07a2SAndy Shevchenko 1479451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1480451e07a2SAndy Shevchenko if (value >= 0) 1481451e07a2SAndy Shevchenko *m = *m * 16 + value; 1482451e07a2SAndy Shevchenko 14831da177e4SLinus Torvalds if (*v == ':') { 14841da177e4SLinus Torvalds m++; 14851da177e4SLinus Torvalds *m = 0; 14861da177e4SLinus Torvalds } 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 1489ce5d0b47SAdit Ranadive /* Set up Src MAC */ 1490ce5d0b47SAdit Ranadive if (compare_ether_addr(old_smac, pkt_dev->src_mac)) 1491ce5d0b47SAdit Ranadive memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); 1492ce5d0b47SAdit Ranadive 14931da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 14941da177e4SLinus Torvalds return count; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 14981da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 14991da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 15001da177e4SLinus Torvalds return count; 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds 15031da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 15041da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 150563adc6fbSStephen Hemminger if (len < 0) 1506222f1806SLuiz Capitulino return len; 150763adc6fbSStephen Hemminger 15081da177e4SLinus Torvalds i += len; 15091da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15101da177e4SLinus Torvalds value = MAX_CFLOWS; 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds pkt_dev->cflows = value; 15131da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15141da177e4SLinus Torvalds return count; 15151da177e4SLinus Torvalds } 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15181da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 151963adc6fbSStephen Hemminger if (len < 0) 1520222f1806SLuiz Capitulino return len; 152163adc6fbSStephen Hemminger 15221da177e4SLinus Torvalds i += len; 15231da177e4SLinus Torvalds pkt_dev->lflow = value; 15241da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15251da177e4SLinus Torvalds return count; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 152845b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 152945b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 153063adc6fbSStephen Hemminger if (len < 0) 153145b270f8SRobert Olsson return len; 153263adc6fbSStephen Hemminger 153345b270f8SRobert Olsson i += len; 153445b270f8SRobert Olsson pkt_dev->queue_map_min = value; 153545b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 153645b270f8SRobert Olsson return count; 153745b270f8SRobert Olsson } 153845b270f8SRobert Olsson 153945b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 154045b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 154163adc6fbSStephen Hemminger if (len < 0) 154245b270f8SRobert Olsson return len; 154363adc6fbSStephen Hemminger 154445b270f8SRobert Olsson i += len; 154545b270f8SRobert Olsson pkt_dev->queue_map_max = value; 154645b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 154745b270f8SRobert Olsson return count; 154845b270f8SRobert Olsson } 154945b270f8SRobert Olsson 1550ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 1551cfcabdccSStephen Hemminger unsigned n, cnt; 1552cfcabdccSStephen Hemminger 1553ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1554cfcabdccSStephen Hemminger if (len < 0) 1555cfcabdccSStephen Hemminger return len; 1556ca6549afSSteven Whitehouse i += len; 1557cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1558ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1559cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1560ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1561ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 156234954ddcSFrancesco Fondelli 156334954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 156434954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 156534954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 156634954ddcSFrancesco Fondelli 156734954ddcSFrancesco Fondelli if (debug) 156825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); 156934954ddcSFrancesco Fondelli } 157034954ddcSFrancesco Fondelli return count; 157134954ddcSFrancesco Fondelli } 157234954ddcSFrancesco Fondelli 157334954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 157434954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 157563adc6fbSStephen Hemminger if (len < 0) 157634954ddcSFrancesco Fondelli return len; 157763adc6fbSStephen Hemminger 157834954ddcSFrancesco Fondelli i += len; 157934954ddcSFrancesco Fondelli if (value <= 4095) { 158034954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 158134954ddcSFrancesco Fondelli 158234954ddcSFrancesco Fondelli if (debug) 158325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN turned on\n"); 158434954ddcSFrancesco Fondelli 158534954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 158625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 158734954ddcSFrancesco Fondelli 158834954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 158934954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 159034954ddcSFrancesco Fondelli } else { 159134954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 159234954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 159334954ddcSFrancesco Fondelli 159434954ddcSFrancesco Fondelli if (debug) 159525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 159634954ddcSFrancesco Fondelli } 159734954ddcSFrancesco Fondelli return count; 159834954ddcSFrancesco Fondelli } 159934954ddcSFrancesco Fondelli 160034954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 160134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 160263adc6fbSStephen Hemminger if (len < 0) 160334954ddcSFrancesco Fondelli return len; 160463adc6fbSStephen Hemminger 160534954ddcSFrancesco Fondelli i += len; 160634954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 160734954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 160834954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 160934954ddcSFrancesco Fondelli } else { 161034954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 161134954ddcSFrancesco Fondelli } 161234954ddcSFrancesco Fondelli return count; 161334954ddcSFrancesco Fondelli } 161434954ddcSFrancesco Fondelli 161534954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 161634954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 161763adc6fbSStephen Hemminger if (len < 0) 161834954ddcSFrancesco Fondelli return len; 161963adc6fbSStephen Hemminger 162034954ddcSFrancesco Fondelli i += len; 162134954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 162234954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 162334954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 162434954ddcSFrancesco Fondelli } else { 162534954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 162634954ddcSFrancesco Fondelli } 162734954ddcSFrancesco Fondelli return count; 162834954ddcSFrancesco Fondelli } 162934954ddcSFrancesco Fondelli 163034954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 163134954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 163263adc6fbSStephen Hemminger if (len < 0) 163334954ddcSFrancesco Fondelli return len; 163463adc6fbSStephen Hemminger 163534954ddcSFrancesco Fondelli i += len; 163634954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 163734954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 163834954ddcSFrancesco Fondelli 163934954ddcSFrancesco Fondelli if (debug) 164025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); 164134954ddcSFrancesco Fondelli 164234954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 164325a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 164434954ddcSFrancesco Fondelli 164534954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 164634954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 164734954ddcSFrancesco Fondelli } else { 164834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 164934954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 165034954ddcSFrancesco Fondelli 165134954ddcSFrancesco Fondelli if (debug) 165225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 165334954ddcSFrancesco Fondelli } 165434954ddcSFrancesco Fondelli return count; 165534954ddcSFrancesco Fondelli } 165634954ddcSFrancesco Fondelli 165734954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 165834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 165963adc6fbSStephen Hemminger if (len < 0) 166034954ddcSFrancesco Fondelli return len; 166163adc6fbSStephen Hemminger 166234954ddcSFrancesco Fondelli i += len; 166334954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 166434954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 166534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 166634954ddcSFrancesco Fondelli } else { 166734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 166834954ddcSFrancesco Fondelli } 166934954ddcSFrancesco Fondelli return count; 167034954ddcSFrancesco Fondelli } 167134954ddcSFrancesco Fondelli 167234954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 167334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 167463adc6fbSStephen Hemminger if (len < 0) 167534954ddcSFrancesco Fondelli return len; 167663adc6fbSStephen Hemminger 167734954ddcSFrancesco Fondelli i += len; 167834954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 167934954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 168034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 168134954ddcSFrancesco Fondelli } else { 168234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 168334954ddcSFrancesco Fondelli } 1684ca6549afSSteven Whitehouse return count; 1685ca6549afSSteven Whitehouse } 1686ca6549afSSteven Whitehouse 16871ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16881ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16891ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 169063adc6fbSStephen Hemminger if (len < 0) 16911ca7768cSFrancesco Fondelli return len; 169263adc6fbSStephen Hemminger 16931ca7768cSFrancesco Fondelli i += len; 16941ca7768cSFrancesco Fondelli if (len == 2) { 16951ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16961ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16971ca7768cSFrancesco Fondelli } else { 16981ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 16991ca7768cSFrancesco Fondelli } 17001ca7768cSFrancesco Fondelli return count; 17011ca7768cSFrancesco Fondelli } 17021ca7768cSFrancesco Fondelli 17031ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 17041ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17051ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 170663adc6fbSStephen Hemminger if (len < 0) 17071ca7768cSFrancesco Fondelli return len; 170863adc6fbSStephen Hemminger 17091ca7768cSFrancesco Fondelli i += len; 17101ca7768cSFrancesco Fondelli if (len == 2) { 17111ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17121ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17131ca7768cSFrancesco Fondelli } else { 17141ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17151ca7768cSFrancesco Fondelli } 17161ca7768cSFrancesco Fondelli return count; 17171ca7768cSFrancesco Fondelli } 17181ca7768cSFrancesco Fondelli 1719*9e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 1720*9e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 1721*9e50e3acSJohn Fastabend if (len < 0) 1722*9e50e3acSJohn Fastabend return len; 1723*9e50e3acSJohn Fastabend 1724*9e50e3acSJohn Fastabend i += len; 1725*9e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 1726*9e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 1727*9e50e3acSJohn Fastabend pkt_dev->skb_priority); 1728*9e50e3acSJohn Fastabend return count; 1729*9e50e3acSJohn Fastabend } 1730*9e50e3acSJohn Fastabend 17311da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17321da177e4SLinus Torvalds return -EINVAL; 17331da177e4SLinus Torvalds } 17341da177e4SLinus Torvalds 1735d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17361da177e4SLinus Torvalds { 1737d50a6b56SStephen Hemminger return single_open(file, pktgen_if_show, PDE(inode)->data); 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds 17409a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1741d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1742d50a6b56SStephen Hemminger .open = pktgen_if_open, 1743d50a6b56SStephen Hemminger .read = seq_read, 1744d50a6b56SStephen Hemminger .llseek = seq_lseek, 1745d50a6b56SStephen Hemminger .write = pktgen_if_write, 1746d50a6b56SStephen Hemminger .release = single_release, 1747d50a6b56SStephen Hemminger }; 1748d50a6b56SStephen Hemminger 1749d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1750d50a6b56SStephen Hemminger { 1751d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1752648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1753d50a6b56SStephen Hemminger 1754d50a6b56SStephen Hemminger BUG_ON(!t); 1755d50a6b56SStephen Hemminger 1756d50a6b56SStephen Hemminger seq_printf(seq, "Running: "); 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds if_lock(t); 1759c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17601da177e4SLinus Torvalds if (pkt_dev->running) 1761593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17621da177e4SLinus Torvalds 1763d50a6b56SStephen Hemminger seq_printf(seq, "\nStopped: "); 17641da177e4SLinus Torvalds 1765c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17661da177e4SLinus Torvalds if (!pkt_dev->running) 1767593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds if (t->result[0]) 1770d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17711da177e4SLinus Torvalds else 1772d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: NA\n"); 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds if_unlock(t); 17751da177e4SLinus Torvalds 1776d50a6b56SStephen Hemminger return 0; 17771da177e4SLinus Torvalds } 17781da177e4SLinus Torvalds 1779d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1780d50a6b56SStephen Hemminger const char __user * user_buffer, 1781d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17821da177e4SLinus Torvalds { 17838a994a71SJoe Perches struct seq_file *seq = file->private_data; 1784d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1785d6182223SPaul Gortmaker int i, max, len, ret; 17861da177e4SLinus Torvalds char name[40]; 17871da177e4SLinus Torvalds char *pg_result; 17881da177e4SLinus Torvalds 17891da177e4SLinus Torvalds if (count < 1) { 17901da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17911da177e4SLinus Torvalds return -EINVAL; 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds 1794d6182223SPaul Gortmaker max = count; 1795d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 17961da177e4SLinus Torvalds if (len < 0) 17971da177e4SLinus Torvalds return len; 17981da177e4SLinus Torvalds 1799d6182223SPaul Gortmaker i = len; 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds /* Read variable name */ 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 18041da177e4SLinus Torvalds if (len < 0) 18051da177e4SLinus Torvalds return len; 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 18081da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 18091da177e4SLinus Torvalds return -EFAULT; 18101da177e4SLinus Torvalds i += len; 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds max = count - i; 18131da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 18141da177e4SLinus Torvalds if (len < 0) 18151da177e4SLinus Torvalds return len; 18161da177e4SLinus Torvalds 18171da177e4SLinus Torvalds i += len; 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds if (debug) 182025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", 182125a8b254SDavid S. Miller name, (unsigned long)count); 18221da177e4SLinus Torvalds 18231da177e4SLinus Torvalds if (!t) { 1824f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 18251da177e4SLinus Torvalds ret = -EINVAL; 18261da177e4SLinus Torvalds goto out; 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds pg_result = &(t->result[0]); 18301da177e4SLinus Torvalds 18311da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18321da177e4SLinus Torvalds char f[32]; 18331da177e4SLinus Torvalds memset(f, 0, 32); 18341da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18351da177e4SLinus Torvalds if (len < 0) { 18361da177e4SLinus Torvalds ret = len; 18371da177e4SLinus Torvalds goto out; 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18401da177e4SLinus Torvalds return -EFAULT; 18411da177e4SLinus Torvalds i += len; 18426146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18431da177e4SLinus Torvalds pktgen_add_device(t, f); 18446146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18451da177e4SLinus Torvalds ret = count; 18461da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 18471da177e4SLinus Torvalds goto out; 18481da177e4SLinus Torvalds } 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18516146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 185295ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18536146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1854121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18551da177e4SLinus Torvalds ret = count; 18561da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18571da177e4SLinus Torvalds goto out; 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1861b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18621da177e4SLinus Torvalds ret = count; 18631da177e4SLinus Torvalds goto out; 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds ret = -EINVAL; 18671da177e4SLinus Torvalds out: 18681da177e4SLinus Torvalds return ret; 18691da177e4SLinus Torvalds } 18701da177e4SLinus Torvalds 1871d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18721da177e4SLinus Torvalds { 1873d50a6b56SStephen Hemminger return single_open(file, pktgen_thread_show, PDE(inode)->data); 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds 18769a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1877d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1878d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1879d50a6b56SStephen Hemminger .read = seq_read, 1880d50a6b56SStephen Hemminger .llseek = seq_lseek, 1881d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1882d50a6b56SStephen Hemminger .release = single_release, 1883d50a6b56SStephen Hemminger }; 18841da177e4SLinus Torvalds 18851da177e4SLinus Torvalds /* Think find or remove for NN */ 18861da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) 18871da177e4SLinus Torvalds { 18881da177e4SLinus Torvalds struct pktgen_thread *t; 18891da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18903e984840SEric Dumazet bool exact = (remove == FIND); 18911da177e4SLinus Torvalds 1892cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 18933e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18941da177e4SLinus Torvalds if (pkt_dev) { 18951da177e4SLinus Torvalds if (remove) { 18961da177e4SLinus Torvalds if_lock(t); 189795ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 189895ed63f7SArthur Kepner t->control |= T_REMDEV; 18991da177e4SLinus Torvalds if_unlock(t); 19001da177e4SLinus Torvalds } 19011da177e4SLinus Torvalds break; 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds return pkt_dev; 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds 190795ed63f7SArthur Kepner /* 190895ed63f7SArthur Kepner * mark a device for removal 190995ed63f7SArthur Kepner */ 191039df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname) 19111da177e4SLinus Torvalds { 19121da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 191395ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 191495ed63f7SArthur Kepner int i = 0; 191595ed63f7SArthur Kepner 19166146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1917f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 191895ed63f7SArthur Kepner 191995ed63f7SArthur Kepner while (1) { 192095ed63f7SArthur Kepner 192195ed63f7SArthur Kepner pkt_dev = __pktgen_NN_threads(ifname, REMOVE); 1922222f1806SLuiz Capitulino if (pkt_dev == NULL) 1923222f1806SLuiz Capitulino break; /* success */ 192495ed63f7SArthur Kepner 19256146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1926f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1927f9467eaeSJoe Perches __func__, ifname); 192895ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19296146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 193095ed63f7SArthur Kepner 193195ed63f7SArthur Kepner if (++i >= max_tries) { 1932f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1933f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 193495ed63f7SArthur Kepner break; 193595ed63f7SArthur Kepner } 193695ed63f7SArthur Kepner 193795ed63f7SArthur Kepner } 193895ed63f7SArthur Kepner 19396146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 194039df232fSStephen Hemminger } 194195ed63f7SArthur Kepner 194239df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev) 194339df232fSStephen Hemminger { 194439df232fSStephen Hemminger struct pktgen_thread *t; 194539df232fSStephen Hemminger 194639df232fSStephen Hemminger list_for_each_entry(t, &pktgen_threads, th_list) { 194739df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 194839df232fSStephen Hemminger 194939df232fSStephen Hemminger list_for_each_entry(pkt_dev, &t->if_list, list) { 195039df232fSStephen Hemminger if (pkt_dev->odev != dev) 195139df232fSStephen Hemminger continue; 195239df232fSStephen Hemminger 195339df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 195439df232fSStephen Hemminger 19552975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19562975315bSAlexey Dobriyan pg_proc_dir, 19572975315bSAlexey Dobriyan &pktgen_if_fops, 19582975315bSAlexey Dobriyan pkt_dev); 195939df232fSStephen Hemminger if (!pkt_dev->entry) 1960f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1961f9467eaeSJoe Perches dev->name); 196239df232fSStephen Hemminger break; 196339df232fSStephen Hemminger } 196439df232fSStephen Hemminger } 19651da177e4SLinus Torvalds } 19661da177e4SLinus Torvalds 1967222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1968222f1806SLuiz Capitulino unsigned long event, void *ptr) 19691da177e4SLinus Torvalds { 197039df232fSStephen Hemminger struct net_device *dev = ptr; 19711da177e4SLinus Torvalds 1972721499e8SYOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 1973e9dc8653SEric W. Biederman return NOTIFY_DONE; 1974e9dc8653SEric W. Biederman 19751da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19761da177e4SLinus Torvalds * as we run under the RTNL lock. 19771da177e4SLinus Torvalds */ 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvalds switch (event) { 198039df232fSStephen Hemminger case NETDEV_CHANGENAME: 198139df232fSStephen Hemminger pktgen_change_name(dev); 19821da177e4SLinus Torvalds break; 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds case NETDEV_UNREGISTER: 198595ed63f7SArthur Kepner pktgen_mark_device(dev->name); 19861da177e4SLinus Torvalds break; 19873ff50b79SStephen Hemminger } 19881da177e4SLinus Torvalds 19891da177e4SLinus Torvalds return NOTIFY_DONE; 19901da177e4SLinus Torvalds } 19911da177e4SLinus Torvalds 199263adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, 199363adc6fbSStephen Hemminger const char *ifname) 1994e6fce5b9SRobert Olsson { 1995e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1996d6182223SPaul Gortmaker int i; 1997e6fce5b9SRobert Olsson 1998e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 1999e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 2000e6fce5b9SRobert Olsson break; 2001e6fce5b9SRobert Olsson 2002e6fce5b9SRobert Olsson b[i] = ifname[i]; 2003e6fce5b9SRobert Olsson } 2004e6fce5b9SRobert Olsson b[i] = 0; 2005e6fce5b9SRobert Olsson 2006e6fce5b9SRobert Olsson return dev_get_by_name(&init_net, b); 2007e6fce5b9SRobert Olsson } 2008e6fce5b9SRobert Olsson 2009e6fce5b9SRobert Olsson 20101da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 20111da177e4SLinus Torvalds 201239df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) 2013222f1806SLuiz Capitulino { 20141da177e4SLinus Torvalds struct net_device *odev; 201539df232fSStephen Hemminger int err; 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds /* Clean old setups */ 20181da177e4SLinus Torvalds if (pkt_dev->odev) { 20191da177e4SLinus Torvalds dev_put(pkt_dev->odev); 20201da177e4SLinus Torvalds pkt_dev->odev = NULL; 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds 2023e6fce5b9SRobert Olsson odev = pktgen_dev_get_by_name(pkt_dev, ifname); 20241da177e4SLinus Torvalds if (!odev) { 2025f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 202639df232fSStephen Hemminger return -ENODEV; 20271da177e4SLinus Torvalds } 202839df232fSStephen Hemminger 20291da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2030f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 203139df232fSStephen Hemminger err = -EINVAL; 203239df232fSStephen Hemminger } else if (!netif_running(odev)) { 2033f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 203439df232fSStephen Hemminger err = -ENETDOWN; 203539df232fSStephen Hemminger } else { 20361da177e4SLinus Torvalds pkt_dev->odev = odev; 203739df232fSStephen Hemminger return 0; 203839df232fSStephen Hemminger } 20391da177e4SLinus Torvalds 20401da177e4SLinus Torvalds dev_put(odev); 204139df232fSStephen Hemminger return err; 20421da177e4SLinus Torvalds } 20431da177e4SLinus Torvalds 20441da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20451da177e4SLinus Torvalds * structure to have the right information to create/send packets 20461da177e4SLinus Torvalds */ 20471da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20481da177e4SLinus Torvalds { 204964c00d81SAndrew Gallatin int ntxq; 205064c00d81SAndrew Gallatin 20511da177e4SLinus Torvalds if (!pkt_dev->odev) { 2052f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2053222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2054222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20551da177e4SLinus Torvalds return; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds 205864c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 205964c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2060bfdbc0acSRobert Olsson 206164c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2062f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 206388271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2064593f63b0SEric Dumazet pkt_dev->odevname); 206564c00d81SAndrew Gallatin pkt_dev->queue_map_min = ntxq - 1; 206664c00d81SAndrew Gallatin } 206788271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2068f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 206988271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2070593f63b0SEric Dumazet pkt_dev->odevname); 207164c00d81SAndrew Gallatin pkt_dev->queue_map_max = ntxq - 1; 207264c00d81SAndrew Gallatin } 207364c00d81SAndrew Gallatin 20741da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20751da177e4SLinus Torvalds 2076f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 2077f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); 20781da177e4SLinus Torvalds 20791da177e4SLinus Torvalds /* Set up Dest MAC */ 2080f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 20811da177e4SLinus Torvalds 20821da177e4SLinus Torvalds /* Set up pkt size */ 20831da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 20841da177e4SLinus Torvalds 20851da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20861da177e4SLinus Torvalds /* 20871da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 20881da177e4SLinus Torvalds * gets exported 20891da177e4SLinus Torvalds */ 20901da177e4SLinus Torvalds 20911da177e4SLinus Torvalds #ifdef NOTNOW 20921da177e4SLinus Torvalds int i, set = 0, err = 1; 20931da177e4SLinus Torvalds struct inet6_dev *idev; 20941da177e4SLinus Torvalds 20951da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20961da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20971da177e4SLinus Torvalds set = 1; 20981da177e4SLinus Torvalds break; 20991da177e4SLinus Torvalds } 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds if (!set) { 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds /* 21041da177e4SLinus Torvalds * Use linklevel address if unconfigured. 21051da177e4SLinus Torvalds * 21061da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 21071da177e4SLinus Torvalds */ 21081da177e4SLinus Torvalds 21098814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 211063adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 211163adc6fbSStephen Hemminger if (idev) { 21121da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 21131da177e4SLinus Torvalds 21141da177e4SLinus Torvalds read_lock_bh(&idev->lock); 2115222f1806SLuiz Capitulino for (ifp = idev->addr_list; ifp; 2116222f1806SLuiz Capitulino ifp = ifp->if_next) { 2117f64f9e71SJoe Perches if (ifp->scope == IFA_LINK && 2118f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 2119222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev-> 2120222f1806SLuiz Capitulino cur_in6_saddr, 2121222f1806SLuiz Capitulino &ifp->addr); 21221da177e4SLinus Torvalds err = 0; 21231da177e4SLinus Torvalds break; 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds } 21261da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 21271da177e4SLinus Torvalds } 21288814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2129222f1806SLuiz Capitulino if (err) 2130f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds #endif 2133222f1806SLuiz Capitulino } else { 21341da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21351da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21361da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21371da177e4SLinus Torvalds 21381da177e4SLinus Torvalds struct in_device *in_dev; 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds rcu_read_lock(); 2141e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21421da177e4SLinus Torvalds if (in_dev) { 21431da177e4SLinus Torvalds if (in_dev->ifa_list) { 2144222f1806SLuiz Capitulino pkt_dev->saddr_min = 2145222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 21461da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds } 21491da177e4SLinus Torvalds rcu_read_unlock(); 2150222f1806SLuiz Capitulino } else { 21511da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21521da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21531da177e4SLinus Torvalds } 21541da177e4SLinus Torvalds 21551da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21561da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21571da177e4SLinus Torvalds } 21581da177e4SLinus Torvalds /* Initialize current values. */ 21591da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21601da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21611da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21621da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21631da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21641da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21651da177e4SLinus Torvalds pkt_dev->nflows = 0; 21661da177e4SLinus Torvalds } 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds 2169fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2170fd29cf72SStephen Hemminger { 2171ef87979cSStephen Hemminger ktime_t start_time, end_time; 2172417bc4b8SEric Dumazet s64 remaining; 21732bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2174fd29cf72SStephen Hemminger 21752bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21762bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2177fd29cf72SStephen Hemminger 217843d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2179417bc4b8SEric Dumazet if (remaining <= 0) { 2180417bc4b8SEric Dumazet pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21811da177e4SLinus Torvalds return; 2182417bc4b8SEric Dumazet } 21832bc481cfSStephen Hemminger 2184ef87979cSStephen Hemminger start_time = ktime_now(); 218543d28b65SDaniel Turull if (remaining < 100000) 218643d28b65SDaniel Turull ndelay(remaining); /* really small just spin */ 21872bc481cfSStephen Hemminger else { 21882bc481cfSStephen Hemminger /* see do_nanosleep */ 21892bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 21902bc481cfSStephen Hemminger do { 21912bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21922bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 21932bc481cfSStephen Hemminger if (!hrtimer_active(&t.timer)) 21942bc481cfSStephen Hemminger t.task = NULL; 21952bc481cfSStephen Hemminger 21962bc481cfSStephen Hemminger if (likely(t.task)) 21971da177e4SLinus Torvalds schedule(); 21981da177e4SLinus Torvalds 21992bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 22002bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 22012bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 22021da177e4SLinus Torvalds } 2203ef87979cSStephen Hemminger end_time = ktime_now(); 2204ef87979cSStephen Hemminger 2205ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 220607a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 22071da177e4SLinus Torvalds } 22081da177e4SLinus Torvalds 220916dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 221016dab72fSJamal Hadi Salim { 2211a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 221216dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 221316dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 221416dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 221516dab72fSJamal Hadi Salim } 221616dab72fSJamal Hadi Salim 2217648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2218007a531bSJamal Hadi Salim { 2219648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2220007a531bSJamal Hadi Salim } 2221007a531bSJamal Hadi Salim 2222007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2223007a531bSJamal Hadi Salim { 2224007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2225007a531bSJamal Hadi Salim 2226007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2227007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2228007a531bSJamal Hadi Salim /* reset time */ 2229007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22301211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2231007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2232007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2233007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2234007a531bSJamal Hadi Salim } 2235007a531bSJamal Hadi Salim } else { 2236007a531bSJamal Hadi Salim flow = random32() % pkt_dev->cflows; 22371211a645SRobert Olsson pkt_dev->curfl = flow; 2238007a531bSJamal Hadi Salim 22391211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2240007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22411211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22421211a645SRobert Olsson } 2243007a531bSJamal Hadi Salim } 2244007a531bSJamal Hadi Salim 2245007a531bSJamal Hadi Salim return pkt_dev->curfl; 2246007a531bSJamal Hadi Salim } 2247007a531bSJamal Hadi Salim 2248a553e4a6SJamal Hadi Salim 2249a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2250a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2251a553e4a6SJamal Hadi Salim * we go look for it ... 2252a553e4a6SJamal Hadi Salim */ 2253bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2254fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2255a553e4a6SJamal Hadi Salim { 2256a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 2257a553e4a6SJamal Hadi Salim if (!x) { 2258a553e4a6SJamal Hadi Salim /*slow path: we dont already have xfrm_state*/ 2259bd55775cSJamal Hadi Salim x = xfrm_stateonly_find(&init_net, DUMMY_MARK, 22605447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2261a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2262a553e4a6SJamal Hadi Salim AF_INET, 2263a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2264a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2265a553e4a6SJamal Hadi Salim if (x) { 2266a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2267a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2268a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2269a553e4a6SJamal Hadi Salim } 2270a553e4a6SJamal Hadi Salim 2271a553e4a6SJamal Hadi Salim } 2272a553e4a6SJamal Hadi Salim } 2273a553e4a6SJamal Hadi Salim #endif 2274fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2275fd2ea0a7SDavid S. Miller { 2276e6fce5b9SRobert Olsson 2277e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2278e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2279e6fce5b9SRobert Olsson 2280896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2281fd2ea0a7SDavid S. Miller __u16 t; 2282fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 2283fd2ea0a7SDavid S. Miller t = random32() % 2284fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2285fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2286fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2287fd2ea0a7SDavid S. Miller } else { 2288fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2289fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2290fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2291fd2ea0a7SDavid S. Miller } 2292fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2293fd2ea0a7SDavid S. Miller } 2294bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2295fd2ea0a7SDavid S. Miller } 2296fd2ea0a7SDavid S. Miller 22971da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 22981da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 22991da177e4SLinus Torvalds */ 2300222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2301222f1806SLuiz Capitulino { 23021da177e4SLinus Torvalds __u32 imn; 23031da177e4SLinus Torvalds __u32 imx; 23041da177e4SLinus Torvalds int flow = 0; 23051da177e4SLinus Torvalds 2306007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2307007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 23081da177e4SLinus Torvalds 23091da177e4SLinus Torvalds /* Deal with source MAC */ 23101da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 23111da177e4SLinus Torvalds __u32 mc; 23121da177e4SLinus Torvalds __u32 tmp; 23131da177e4SLinus Torvalds 23141da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 23155fa6fc76SStephen Hemminger mc = random32() % pkt_dev->src_mac_count; 23161da177e4SLinus Torvalds else { 23171da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2318ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2319222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23201da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23211da177e4SLinus Torvalds } 23221da177e4SLinus Torvalds 23231da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23241da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23251da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23261da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23271da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23281da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23291da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23301da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23311da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23321da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23331da177e4SLinus Torvalds } 23341da177e4SLinus Torvalds 23351da177e4SLinus Torvalds /* Deal with Destination MAC */ 23361da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23371da177e4SLinus Torvalds __u32 mc; 23381da177e4SLinus Torvalds __u32 tmp; 23391da177e4SLinus Torvalds 23401da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 23415fa6fc76SStephen Hemminger mc = random32() % pkt_dev->dst_mac_count; 23421da177e4SLinus Torvalds 23431da177e4SLinus Torvalds else { 23441da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2345ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2346222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23471da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23481da177e4SLinus Torvalds } 23491da177e4SLinus Torvalds } 23501da177e4SLinus Torvalds 23511da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23521da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23531da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23541da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23551da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23561da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23571da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23581da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23591da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23601da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds 2363ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 2364ca6549afSSteven Whitehouse unsigned i; 2365ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2366ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2367ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 23685fa6fc76SStephen Hemminger ((__force __be32)random32() & 2369ca6549afSSteven Whitehouse htonl(0x000fffff)); 2370ca6549afSSteven Whitehouse } 2371ca6549afSSteven Whitehouse 237234954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 23735fa6fc76SStephen Hemminger pkt_dev->vlan_id = random32() & (4096-1); 237434954ddcSFrancesco Fondelli } 237534954ddcSFrancesco Fondelli 237634954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 23775fa6fc76SStephen Hemminger pkt_dev->svlan_id = random32() & (4096 - 1); 237834954ddcSFrancesco Fondelli } 237934954ddcSFrancesco Fondelli 23801da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23811da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 23825fa6fc76SStephen Hemminger pkt_dev->cur_udp_src = random32() % 23835fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23845fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23851da177e4SLinus Torvalds 23861da177e4SLinus Torvalds else { 23871da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 23881da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23891da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23901da177e4SLinus Torvalds } 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 23931da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23941da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 23955fa6fc76SStephen Hemminger pkt_dev->cur_udp_dst = random32() % 23965fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23975fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2398222f1806SLuiz Capitulino } else { 23991da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 24001da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 24011da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds 24051da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 24061da177e4SLinus Torvalds 240763adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 240863adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 240963adc6fbSStephen Hemminger if (imn < imx) { 24101da177e4SLinus Torvalds __u32 t; 24111da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 24125fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 24131da177e4SLinus Torvalds else { 24141da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 24151da177e4SLinus Torvalds t++; 241663adc6fbSStephen Hemminger if (t > imx) 24171da177e4SLinus Torvalds t = imn; 241863adc6fbSStephen Hemminger 24191da177e4SLinus Torvalds } 24201da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24211da177e4SLinus Torvalds } 24221da177e4SLinus Torvalds 2423007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24241da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24251da177e4SLinus Torvalds } else { 2426252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2427252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2428252e3346SAl Viro if (imn < imx) { 24291da177e4SLinus Torvalds __u32 t; 2430252e3346SAl Viro __be32 s; 24311da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24321da177e4SLinus Torvalds 24335fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2434252e3346SAl Viro s = htonl(t); 24351da177e4SLinus Torvalds 243621cf2253SJoe Perches while (ipv4_is_loopback(s) || 243721cf2253SJoe Perches ipv4_is_multicast(s) || 24381e637c74SJan Engelhardt ipv4_is_lbcast(s) || 243921cf2253SJoe Perches ipv4_is_zeronet(s) || 244021cf2253SJoe Perches ipv4_is_local_multicast(s)) { 24415fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2442252e3346SAl Viro s = htonl(t); 24431da177e4SLinus Torvalds } 2444252e3346SAl Viro pkt_dev->cur_daddr = s; 2445252e3346SAl Viro } else { 24461da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24471da177e4SLinus Torvalds t++; 24481da177e4SLinus Torvalds if (t > imx) { 24491da177e4SLinus Torvalds t = imn; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24521da177e4SLinus Torvalds } 24531da177e4SLinus Torvalds } 24541da177e4SLinus Torvalds if (pkt_dev->cflows) { 2455007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2456222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2457222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2458a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2459a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2460a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2461a553e4a6SJamal Hadi Salim #endif 24621da177e4SLinus Torvalds pkt_dev->nflows++; 24631da177e4SLinus Torvalds } 24641da177e4SLinus Torvalds } 2465222f1806SLuiz Capitulino } else { /* IPV6 * */ 2466222f1806SLuiz Capitulino 24671da177e4SLinus Torvalds if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 24681da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 24691da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 24701da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; 24711da177e4SLinus Torvalds else { 24721da177e4SLinus Torvalds int i; 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds /* Only random destinations yet */ 24751da177e4SLinus Torvalds 24761da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24771da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 24785fa6fc76SStephen Hemminger (((__force __be32)random32() | 24791da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24801da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24811da177e4SLinus Torvalds } 24821da177e4SLinus Torvalds } 24831da177e4SLinus Torvalds } 24841da177e4SLinus Torvalds 24851da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24861da177e4SLinus Torvalds __u32 t; 24871da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 24885fa6fc76SStephen Hemminger t = random32() % 24895fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24905fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2491222f1806SLuiz Capitulino } else { 24921da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 24931da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 24941da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 24971da177e4SLinus Torvalds } 24981da177e4SLinus Torvalds 2499fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 250045b270f8SRobert Olsson 25011da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 25021da177e4SLinus Torvalds } 25031da177e4SLinus Torvalds 2504a553e4a6SJamal Hadi Salim 2505a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2506a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2507a553e4a6SJamal Hadi Salim { 2508a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2509a553e4a6SJamal Hadi Salim int err = 0; 2510a553e4a6SJamal Hadi Salim struct iphdr *iph; 2511a553e4a6SJamal Hadi Salim 2512a553e4a6SJamal Hadi Salim if (!x) 2513a553e4a6SJamal Hadi Salim return 0; 2514a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2515a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2516a553e4a6SJamal Hadi Salim if (x->props.mode != XFRM_MODE_TRANSPORT) 2517a553e4a6SJamal Hadi Salim return 0; 2518a553e4a6SJamal Hadi Salim 2519a553e4a6SJamal Hadi Salim spin_lock(&x->lock); 2520a553e4a6SJamal Hadi Salim iph = ip_hdr(skb); 2521a553e4a6SJamal Hadi Salim 252213996378SHerbert Xu err = x->outer_mode->output(x, skb); 2523a553e4a6SJamal Hadi Salim if (err) 2524a553e4a6SJamal Hadi Salim goto error; 2525a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 2526a553e4a6SJamal Hadi Salim if (err) 2527a553e4a6SJamal Hadi Salim goto error; 2528a553e4a6SJamal Hadi Salim 2529a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2530a553e4a6SJamal Hadi Salim x->curlft.packets++; 2531a553e4a6SJamal Hadi Salim error: 2532a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2533a553e4a6SJamal Hadi Salim return err; 2534a553e4a6SJamal Hadi Salim } 2535a553e4a6SJamal Hadi Salim 2536475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2537a553e4a6SJamal Hadi Salim { 2538a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2539a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2540d6182223SPaul Gortmaker int i; 2541d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2542a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2543a553e4a6SJamal Hadi Salim if (x) { 2544a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2545a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2546a553e4a6SJamal Hadi Salim } 2547a553e4a6SJamal Hadi Salim } 2548a553e4a6SJamal Hadi Salim } 2549a553e4a6SJamal Hadi Salim } 2550a553e4a6SJamal Hadi Salim 2551475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2552a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2553a553e4a6SJamal Hadi Salim { 2554a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2555a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2556a553e4a6SJamal Hadi Salim int nhead = 0; 2557a553e4a6SJamal Hadi Salim if (x) { 2558a553e4a6SJamal Hadi Salim int ret; 2559a553e4a6SJamal Hadi Salim __u8 *eth; 2560a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2561a553e4a6SJamal Hadi Salim if (nhead > 0) { 2562a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2563a553e4a6SJamal Hadi Salim if (ret < 0) { 2564f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2565f9467eaeSJoe Perches ret); 2566b4bb4ac8SIlpo Järvinen goto err; 2567a553e4a6SJamal Hadi Salim } 2568a553e4a6SJamal Hadi Salim } 2569a553e4a6SJamal Hadi Salim 2570a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2571a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2572a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2573a553e4a6SJamal Hadi Salim if (ret) { 2574f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2575b4bb4ac8SIlpo Järvinen goto err; 2576a553e4a6SJamal Hadi Salim } 2577a553e4a6SJamal Hadi Salim /* restore ll */ 2578a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2579a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2580a553e4a6SJamal Hadi Salim *(u16 *) ð[12] = protocol; 2581a553e4a6SJamal Hadi Salim } 2582a553e4a6SJamal Hadi Salim } 2583a553e4a6SJamal Hadi Salim return 1; 2584b4bb4ac8SIlpo Järvinen err: 2585b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2586b4bb4ac8SIlpo Järvinen return 0; 2587a553e4a6SJamal Hadi Salim } 2588a553e4a6SJamal Hadi Salim #endif 2589a553e4a6SJamal Hadi Salim 2590ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2591ca6549afSSteven Whitehouse { 2592ca6549afSSteven Whitehouse unsigned i; 259363adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2594ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 259563adc6fbSStephen Hemminger 2596ca6549afSSteven Whitehouse mpls--; 2597ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2598ca6549afSSteven Whitehouse } 2599ca6549afSSteven Whitehouse 26000f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 26010f37c605SAl Viro unsigned int prio) 26020f37c605SAl Viro { 26030f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 26040f37c605SAl Viro } 26050f37c605SAl Viro 26061da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 26071da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 26081da177e4SLinus Torvalds { 26091da177e4SLinus Torvalds struct sk_buff *skb = NULL; 26101da177e4SLinus Torvalds __u8 *eth; 26111da177e4SLinus Torvalds struct udphdr *udph; 26121da177e4SLinus Torvalds int datalen, iplen; 26131da177e4SLinus Torvalds struct iphdr *iph; 26141da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2615d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2616ca6549afSSteven Whitehouse __be32 *mpls; 261734954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 261834954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 261934954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 262034954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2621fd2ea0a7SDavid S. Miller u16 queue_map; 2622ca6549afSSteven Whitehouse 2623ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2624d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 26251da177e4SLinus Torvalds 262634954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2627d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 262834954ddcSFrancesco Fondelli 262964053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 263064053beeSRobert Olsson * fields. 263164053beeSRobert Olsson */ 263264053beeSRobert Olsson mod_cur_headers(pkt_dev); 2633eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 263464053beeSRobert Olsson 26357ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2636e99b99b4SRobert Olsson 2637e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) { 2638e99b99b4SRobert Olsson int node; 2639e99b99b4SRobert Olsson 2640e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 2641e99b99b4SRobert Olsson node = pkt_dev->node; 2642e99b99b4SRobert Olsson else 2643e99b99b4SRobert Olsson node = numa_node_id(); 2644e99b99b4SRobert Olsson 2645e99b99b4SRobert Olsson skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64 2646e99b99b4SRobert Olsson + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node); 2647e99b99b4SRobert Olsson if (likely(skb)) { 2648e99b99b4SRobert Olsson skb_reserve(skb, NET_SKB_PAD); 2649e99b99b4SRobert Olsson skb->dev = odev; 2650e99b99b4SRobert Olsson } 2651e99b99b4SRobert Olsson } 2652e99b99b4SRobert Olsson else 2653e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2654e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2655e470757dSStephen Hemminger + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); 2656e99b99b4SRobert Olsson 26571da177e4SLinus Torvalds if (!skb) { 26581da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 26591da177e4SLinus Torvalds return NULL; 26601da177e4SLinus Torvalds } 26611da177e4SLinus Torvalds 26627ac5459eSDavid S. Miller skb_reserve(skb, datalen); 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 26651da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2666ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2667ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2668ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 266934954ddcSFrancesco Fondelli 267034954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 267134954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 267234954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26730f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 26740f37c605SAl Viro pkt_dev->svlan_cfi, 26750f37c605SAl Viro pkt_dev->svlan_p); 267634954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2677d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 267834954ddcSFrancesco Fondelli } 267934954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26800f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 26810f37c605SAl Viro pkt_dev->vlan_cfi, 26820f37c605SAl Viro pkt_dev->vlan_p); 268334954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2684d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 268534954ddcSFrancesco Fondelli } 268634954ddcSFrancesco Fondelli 268727a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2688b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct iphdr); 2689ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2690fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 2691*9e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 2692*9e50e3acSJohn Fastabend 2693ddc7b8e3SArnaldo Carvalho de Melo iph = ip_hdr(skb); 2694ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 26951da177e4SLinus Torvalds 26961da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2697252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 26981da177e4SLinus Torvalds 2699ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2700ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 270116dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 27021da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 27031da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 27041da177e4SLinus Torvalds 27051da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 27061da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 27071da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 27081da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 27091da177e4SLinus Torvalds 27101da177e4SLinus Torvalds iph->ihl = 5; 27111da177e4SLinus Torvalds iph->version = 4; 27121da177e4SLinus Torvalds iph->ttl = 32; 27131ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 27141da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 27151da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 27161da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 271766ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 271866ed1e5eSEric Dumazet pkt_dev->ip_id++; 27191da177e4SLinus Torvalds iph->frag_off = 0; 27201da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 27211da177e4SLinus Torvalds iph->tot_len = htons(iplen); 27221da177e4SLinus Torvalds iph->check = 0; 27231da177e4SLinus Torvalds iph->check = ip_fast_csum((void *)iph, iph->ihl); 2724ca6549afSSteven Whitehouse skb->protocol = protocol; 2725b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 272616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 27271da177e4SLinus Torvalds skb->dev = odev; 27281da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 27291da177e4SLinus Torvalds 273066ed1e5eSEric Dumazet if (pkt_dev->nfrags <= 0) { 27311da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 273266ed1e5eSEric Dumazet memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); 273366ed1e5eSEric Dumazet } else { 27341da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 273566ed1e5eSEric Dumazet int i, len; 27361da177e4SLinus Torvalds 27371da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 27381da177e4SLinus Torvalds 27391da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 27401da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 27411da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 274266ed1e5eSEric Dumazet len = datalen - frags * PAGE_SIZE; 274366ed1e5eSEric Dumazet memset(skb_put(skb, len), 0, len); 27441da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 27451da177e4SLinus Torvalds } 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds i = 0; 27481da177e4SLinus Torvalds while (datalen > 0) { 274966ed1e5eSEric Dumazet struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); 27501da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 27511da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 27521da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 27531da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 27541da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 27551da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 27561da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 27571da177e4SLinus Torvalds i++; 27581da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27591da177e4SLinus Torvalds } 27601da177e4SLinus Torvalds 27611da177e4SLinus Torvalds while (i < frags) { 27621da177e4SLinus Torvalds int rem; 27631da177e4SLinus Torvalds 27641da177e4SLinus Torvalds if (i == 0) 27651da177e4SLinus Torvalds break; 27661da177e4SLinus Torvalds 27671da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 27681da177e4SLinus Torvalds if (rem == 0) 27691da177e4SLinus Torvalds break; 27701da177e4SLinus Torvalds 27711da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 27721da177e4SLinus Torvalds 2773222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2774222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 27751da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2776222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2777222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2778222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2779222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 27801da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 27811da177e4SLinus Torvalds i++; 27821da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27831da177e4SLinus Torvalds } 27841da177e4SLinus Torvalds } 27851da177e4SLinus Torvalds 278663adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 278763adc6fbSStephen Hemminger * convert them to network byte order 278863adc6fbSStephen Hemminger */ 27891da177e4SLinus Torvalds if (pgh) { 27901da177e4SLinus Torvalds struct timeval timestamp; 27911da177e4SLinus Torvalds 27921da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 27931da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 27941da177e4SLinus Torvalds 27951da177e4SLinus Torvalds do_gettimeofday(×tamp); 27961da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 27971da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 27981da177e4SLinus Torvalds } 27991da177e4SLinus Torvalds 2800a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2801a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2802a553e4a6SJamal Hadi Salim return NULL; 2803a553e4a6SJamal Hadi Salim #endif 2804a553e4a6SJamal Hadi Salim 28051da177e4SLinus Torvalds return skb; 28061da177e4SLinus Torvalds } 28071da177e4SLinus Torvalds 28081da177e4SLinus Torvalds /* 28091da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 28101da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 28111da177e4SLinus Torvalds * 28121da177e4SLinus Torvalds * Slightly modified for kernel. 28131da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 28141da177e4SLinus Torvalds * --ro 28151da177e4SLinus Torvalds */ 28161da177e4SLinus Torvalds 28171da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]) 28181da177e4SLinus Torvalds { 28191da177e4SLinus Torvalds unsigned int i; 28201da177e4SLinus Torvalds unsigned int len = 0; 28211da177e4SLinus Torvalds unsigned long u; 28221da177e4SLinus Torvalds char suffix[16]; 28231da177e4SLinus Torvalds unsigned int prefixlen = 0; 28241da177e4SLinus Torvalds unsigned int suffixlen = 0; 2825252e3346SAl Viro __be32 tmp; 2826cfcabdccSStephen Hemminger char *pos; 28271da177e4SLinus Torvalds 2828222f1806SLuiz Capitulino for (i = 0; i < 16; i++) 2829222f1806SLuiz Capitulino ip[i] = 0; 28301da177e4SLinus Torvalds 28311da177e4SLinus Torvalds for (;;) { 28321da177e4SLinus Torvalds if (*s == ':') { 28331da177e4SLinus Torvalds len++; 28341da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 28351da177e4SLinus Torvalds s += 2; 28361da177e4SLinus Torvalds len++; 28371da177e4SLinus Torvalds break; 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds s++; 28401da177e4SLinus Torvalds } 28411da177e4SLinus Torvalds 2842cfcabdccSStephen Hemminger u = simple_strtoul(s, &pos, 16); 2843cfcabdccSStephen Hemminger i = pos - s; 2844222f1806SLuiz Capitulino if (!i) 2845222f1806SLuiz Capitulino return 0; 28461da177e4SLinus Torvalds if (prefixlen == 12 && s[i] == '.') { 28471da177e4SLinus Torvalds 28481da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 28491da177e4SLinus Torvalds 28501da177e4SLinus Torvalds tmp = in_aton(s); 28511da177e4SLinus Torvalds memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); 28521da177e4SLinus Torvalds return i + len; 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 28551da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2856222f1806SLuiz Capitulino s += i; 2857222f1806SLuiz Capitulino len += i; 28581da177e4SLinus Torvalds if (prefixlen == 16) 28591da177e4SLinus Torvalds return len; 28601da177e4SLinus Torvalds } 28611da177e4SLinus Torvalds 28621da177e4SLinus Torvalds /* part 2, after "::" */ 28631da177e4SLinus Torvalds for (;;) { 28641da177e4SLinus Torvalds if (*s == ':') { 28651da177e4SLinus Torvalds if (suffixlen == 0) 28661da177e4SLinus Torvalds break; 28671da177e4SLinus Torvalds s++; 28681da177e4SLinus Torvalds len++; 28691da177e4SLinus Torvalds } else if (suffixlen != 0) 28701da177e4SLinus Torvalds break; 2871cfcabdccSStephen Hemminger 2872cfcabdccSStephen Hemminger u = simple_strtol(s, &pos, 16); 2873cfcabdccSStephen Hemminger i = pos - s; 28741da177e4SLinus Torvalds if (!i) { 2875222f1806SLuiz Capitulino if (*s) 2876222f1806SLuiz Capitulino len--; 28771da177e4SLinus Torvalds break; 28781da177e4SLinus Torvalds } 28791da177e4SLinus Torvalds if (suffixlen + prefixlen <= 12 && s[i] == '.') { 28801da177e4SLinus Torvalds tmp = in_aton(s); 2881222f1806SLuiz Capitulino memcpy((struct in_addr *)(suffix + suffixlen), &tmp, 2882222f1806SLuiz Capitulino sizeof(tmp)); 28831da177e4SLinus Torvalds suffixlen += 4; 28841da177e4SLinus Torvalds len += strlen(s); 28851da177e4SLinus Torvalds break; 28861da177e4SLinus Torvalds } 28871da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 28881da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2889222f1806SLuiz Capitulino s += i; 2890222f1806SLuiz Capitulino len += i; 28911da177e4SLinus Torvalds if (prefixlen + suffixlen == 16) 28921da177e4SLinus Torvalds break; 28931da177e4SLinus Torvalds } 28941da177e4SLinus Torvalds for (i = 0; i < suffixlen; i++) 28951da177e4SLinus Torvalds ip[16 - suffixlen + i] = suffix[i]; 28961da177e4SLinus Torvalds return len; 28971da177e4SLinus Torvalds } 28981da177e4SLinus Torvalds 2899222f1806SLuiz Capitulino static char tohex(char hexdigit) 2900222f1806SLuiz Capitulino { 29011da177e4SLinus Torvalds return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; 29021da177e4SLinus Torvalds } 29031da177e4SLinus Torvalds 2904222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i) 2905222f1806SLuiz Capitulino { 29061da177e4SLinus Torvalds char *bak = s; 2907222f1806SLuiz Capitulino *s = tohex((i >> 12) & 0xf); 2908222f1806SLuiz Capitulino if (s != bak || *s != '0') 2909222f1806SLuiz Capitulino ++s; 2910222f1806SLuiz Capitulino *s = tohex((i >> 8) & 0xf); 2911222f1806SLuiz Capitulino if (s != bak || *s != '0') 2912222f1806SLuiz Capitulino ++s; 2913222f1806SLuiz Capitulino *s = tohex((i >> 4) & 0xf); 2914222f1806SLuiz Capitulino if (s != bak || *s != '0') 2915222f1806SLuiz Capitulino ++s; 29161da177e4SLinus Torvalds *s = tohex(i & 0xf); 29171da177e4SLinus Torvalds return s - bak + 1; 29181da177e4SLinus Torvalds } 29191da177e4SLinus Torvalds 2920222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16]) 2921222f1806SLuiz Capitulino { 29221da177e4SLinus Torvalds unsigned int len; 29231da177e4SLinus Torvalds unsigned int i; 29241da177e4SLinus Torvalds unsigned int temp; 29251da177e4SLinus Torvalds unsigned int compressing; 29261da177e4SLinus Torvalds int j; 29271da177e4SLinus Torvalds 2928222f1806SLuiz Capitulino len = 0; 2929222f1806SLuiz Capitulino compressing = 0; 29301da177e4SLinus Torvalds for (j = 0; j < 16; j += 2) { 29311da177e4SLinus Torvalds 29321da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 29331da177e4SLinus Torvalds if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { 29341da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr *)(ip + 12), s); 29351da177e4SLinus Torvalds temp = strlen(s); 29361da177e4SLinus Torvalds return len + temp; 29371da177e4SLinus Torvalds } 29381da177e4SLinus Torvalds #endif 29391da177e4SLinus Torvalds temp = ((unsigned long)(unsigned char)ip[j] << 8) + 29401da177e4SLinus Torvalds (unsigned long)(unsigned char)ip[j + 1]; 29411da177e4SLinus Torvalds if (temp == 0) { 29421da177e4SLinus Torvalds if (!compressing) { 29431da177e4SLinus Torvalds compressing = 1; 29441da177e4SLinus Torvalds if (j == 0) { 2945222f1806SLuiz Capitulino *s++ = ':'; 2946222f1806SLuiz Capitulino ++len; 29471da177e4SLinus Torvalds } 29481da177e4SLinus Torvalds } 29491da177e4SLinus Torvalds } else { 29501da177e4SLinus Torvalds if (compressing) { 29511da177e4SLinus Torvalds compressing = 0; 2952222f1806SLuiz Capitulino *s++ = ':'; 2953222f1806SLuiz Capitulino ++len; 29541da177e4SLinus Torvalds } 2955222f1806SLuiz Capitulino i = fmt_xlong(s, temp); 2956222f1806SLuiz Capitulino len += i; 2957222f1806SLuiz Capitulino s += i; 29581da177e4SLinus Torvalds if (j < 14) { 29591da177e4SLinus Torvalds *s++ = ':'; 29601da177e4SLinus Torvalds ++len; 29611da177e4SLinus Torvalds } 29621da177e4SLinus Torvalds } 29631da177e4SLinus Torvalds } 29641da177e4SLinus Torvalds if (compressing) { 2965222f1806SLuiz Capitulino *s++ = ':'; 2966222f1806SLuiz Capitulino ++len; 29671da177e4SLinus Torvalds } 29681da177e4SLinus Torvalds *s = 0; 29691da177e4SLinus Torvalds return len; 29701da177e4SLinus Torvalds } 29711da177e4SLinus Torvalds 29721da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29731da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29741da177e4SLinus Torvalds { 29751da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29761da177e4SLinus Torvalds __u8 *eth; 29771da177e4SLinus Torvalds struct udphdr *udph; 29781da177e4SLinus Torvalds int datalen; 29791da177e4SLinus Torvalds struct ipv6hdr *iph; 29801da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2981d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2982ca6549afSSteven Whitehouse __be32 *mpls; 298334954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 298434954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 298534954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 298634954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2987fd2ea0a7SDavid S. Miller u16 queue_map; 2988ca6549afSSteven Whitehouse 2989ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2990d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 29911da177e4SLinus Torvalds 299234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2993d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 299434954ddcSFrancesco Fondelli 299564053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 299664053beeSRobert Olsson * fields. 299764053beeSRobert Olsson */ 299864053beeSRobert Olsson mod_cur_headers(pkt_dev); 2999eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 300064053beeSRobert Olsson 3001e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 3002e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 3003e470757dSStephen Hemminger + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT); 30041da177e4SLinus Torvalds if (!skb) { 30051da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 30061da177e4SLinus Torvalds return NULL; 30071da177e4SLinus Torvalds } 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds skb_reserve(skb, 16); 30101da177e4SLinus Torvalds 30111da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 30121da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 3013ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 3014ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 3015ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 301634954ddcSFrancesco Fondelli 301734954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 301834954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 301934954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30200f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30210f37c605SAl Viro pkt_dev->svlan_cfi, 30220f37c605SAl Viro pkt_dev->svlan_p); 302334954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3024d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 302534954ddcSFrancesco Fondelli } 302634954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30270f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30280f37c605SAl Viro pkt_dev->vlan_cfi, 30290f37c605SAl Viro pkt_dev->vlan_p); 303034954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3031d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 303234954ddcSFrancesco Fondelli } 303334954ddcSFrancesco Fondelli 303427a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 3035b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 3036ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 3037fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 3038*9e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 3039ddc7b8e3SArnaldo Carvalho de Melo iph = ipv6_hdr(skb); 3040ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3043252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30441da177e4SLinus Torvalds 3045ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3046ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3047ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 304816dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30491da177e4SLinus Torvalds 30501da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 30511da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 30521da177e4SLinus Torvalds if (net_ratelimit()) 3053f9467eaeSJoe Perches pr_info("increased datalen to %d\n", datalen); 30541da177e4SLinus Torvalds } 30551da177e4SLinus Torvalds 30561da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30571da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 30581da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 30591da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 30601da177e4SLinus Torvalds 3061d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30621da177e4SLinus Torvalds 30631ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30641ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3065252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30661ca7768cSFrancesco Fondelli } 30671ca7768cSFrancesco Fondelli 30681da177e4SLinus Torvalds iph->hop_limit = 32; 30691da177e4SLinus Torvalds 30701da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 30711da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30721da177e4SLinus Torvalds 30731da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 30741da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 30751da177e4SLinus Torvalds 3076b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 307716dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 3078ca6549afSSteven Whitehouse skb->protocol = protocol; 30791da177e4SLinus Torvalds skb->dev = odev; 30801da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30811da177e4SLinus Torvalds 30821da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 30831da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 30841da177e4SLinus Torvalds else { 30851da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 30861da177e4SLinus Torvalds int i; 30871da177e4SLinus Torvalds 30881da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 30891da177e4SLinus Torvalds 30901da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 30911da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 30921da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 30931da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 30941da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 30951da177e4SLinus Torvalds } 30961da177e4SLinus Torvalds 30971da177e4SLinus Torvalds i = 0; 30981da177e4SLinus Torvalds while (datalen > 0) { 30991da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 31001da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 31011da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 31021da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 31031da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 31041da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 31051da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 31061da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 31071da177e4SLinus Torvalds i++; 31081da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31091da177e4SLinus Torvalds } 31101da177e4SLinus Torvalds 31111da177e4SLinus Torvalds while (i < frags) { 31121da177e4SLinus Torvalds int rem; 31131da177e4SLinus Torvalds 31141da177e4SLinus Torvalds if (i == 0) 31151da177e4SLinus Torvalds break; 31161da177e4SLinus Torvalds 31171da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 31181da177e4SLinus Torvalds if (rem == 0) 31191da177e4SLinus Torvalds break; 31201da177e4SLinus Torvalds 31211da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 31221da177e4SLinus Torvalds 3123222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 3124222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 31251da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 3126222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 3127222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 3128222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 3129222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 31301da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 31311da177e4SLinus Torvalds i++; 31321da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31331da177e4SLinus Torvalds } 31341da177e4SLinus Torvalds } 31351da177e4SLinus Torvalds 313663adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 313763adc6fbSStephen Hemminger * convert them to network byte order 313863adc6fbSStephen Hemminger * should we update cloned packets too ? 313963adc6fbSStephen Hemminger */ 31401da177e4SLinus Torvalds if (pgh) { 31411da177e4SLinus Torvalds struct timeval timestamp; 31421da177e4SLinus Torvalds 31431da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 31441da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 31451da177e4SLinus Torvalds 31461da177e4SLinus Torvalds do_gettimeofday(×tamp); 31471da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 31481da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 31491da177e4SLinus Torvalds } 315034954ddcSFrancesco Fondelli /* pkt_dev->seq_num++; FF: you really mean this? */ 31511da177e4SLinus Torvalds 31521da177e4SLinus Torvalds return skb; 31531da177e4SLinus Torvalds } 31541da177e4SLinus Torvalds 3155475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 31561da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 31571da177e4SLinus Torvalds { 31581da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 31591da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 31601da177e4SLinus Torvalds else 31611da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 31621da177e4SLinus Torvalds } 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 31651da177e4SLinus Torvalds { 31661da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31671da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31681da177e4SLinus Torvalds pkt_dev->sofar = 0; 31691da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31701da177e4SLinus Torvalds pkt_dev->errors = 0; 31711da177e4SLinus Torvalds } 31721da177e4SLinus Torvalds 31731da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31761da177e4SLinus Torvalds { 3177c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31781da177e4SLinus Torvalds int started = 0; 31791da177e4SLinus Torvalds 3180f9467eaeSJoe Perches func_enter(); 31811da177e4SLinus Torvalds 31821da177e4SLinus Torvalds if_lock(t); 3183c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 31841da177e4SLinus Torvalds 31851da177e4SLinus Torvalds /* 31861da177e4SLinus Torvalds * setup odev and create initial packet. 31871da177e4SLinus Torvalds */ 31881da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31891da177e4SLinus Torvalds 31901da177e4SLinus Torvalds if (pkt_dev->odev) { 31911da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31921da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 31931da177e4SLinus Torvalds pkt_dev->skb = NULL; 3194fd29cf72SStephen Hemminger pkt_dev->started_at = 3195fd29cf72SStephen Hemminger pkt_dev->next_tx = ktime_now(); 3196fd29cf72SStephen Hemminger 319716dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 31981da177e4SLinus Torvalds 31991da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 32001da177e4SLinus Torvalds started++; 3201222f1806SLuiz Capitulino } else 32021da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 32031da177e4SLinus Torvalds } 32041da177e4SLinus Torvalds if_unlock(t); 3205222f1806SLuiz Capitulino if (started) 3206222f1806SLuiz Capitulino t->control &= ~(T_STOP); 32071da177e4SLinus Torvalds } 32081da177e4SLinus Torvalds 32091da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 32101da177e4SLinus Torvalds { 3211cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32121da177e4SLinus Torvalds 3213f9467eaeSJoe Perches func_enter(); 32141da177e4SLinus Torvalds 32156146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3216cdcdbe0bSLuiz Capitulino 3217cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 321895ed63f7SArthur Kepner t->control |= T_STOP; 3219cdcdbe0bSLuiz Capitulino 32206146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32211da177e4SLinus Torvalds } 32221da177e4SLinus Torvalds 3223648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 32241da177e4SLinus Torvalds { 3225648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 32261da177e4SLinus Torvalds 3227c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 3228648fda74SStephen Hemminger if (pkt_dev->running) 3229648fda74SStephen Hemminger return 1; 3230648fda74SStephen Hemminger return 0; 32311da177e4SLinus Torvalds } 32321da177e4SLinus Torvalds 32331da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 32341da177e4SLinus Torvalds { 32351da177e4SLinus Torvalds if_lock(t); 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds while (thread_is_running(t)) { 32381da177e4SLinus Torvalds 32391da177e4SLinus Torvalds if_unlock(t); 32401da177e4SLinus Torvalds 32411da177e4SLinus Torvalds msleep_interruptible(100); 32421da177e4SLinus Torvalds 32431da177e4SLinus Torvalds if (signal_pending(current)) 32441da177e4SLinus Torvalds goto signal; 32451da177e4SLinus Torvalds if_lock(t); 32461da177e4SLinus Torvalds } 32471da177e4SLinus Torvalds if_unlock(t); 32481da177e4SLinus Torvalds return 1; 32491da177e4SLinus Torvalds signal: 32501da177e4SLinus Torvalds return 0; 32511da177e4SLinus Torvalds } 32521da177e4SLinus Torvalds 32531da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 32541da177e4SLinus Torvalds { 3255cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32561da177e4SLinus Torvalds int sig = 1; 32571da177e4SLinus Torvalds 32586146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3259cdcdbe0bSLuiz Capitulino 3260cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 32611da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3262222f1806SLuiz Capitulino if (sig == 0) 3263222f1806SLuiz Capitulino break; 32641da177e4SLinus Torvalds } 3265cdcdbe0bSLuiz Capitulino 3266cdcdbe0bSLuiz Capitulino if (sig == 0) 3267cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32681da177e4SLinus Torvalds t->control |= (T_STOP); 3269cdcdbe0bSLuiz Capitulino 32706146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32711da177e4SLinus Torvalds return sig; 32721da177e4SLinus Torvalds } 32731da177e4SLinus Torvalds 32741da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 32751da177e4SLinus Torvalds { 3276cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32771da177e4SLinus Torvalds 3278f9467eaeSJoe Perches func_enter(); 32791da177e4SLinus Torvalds 32806146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 32811da177e4SLinus Torvalds 3282cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32831da177e4SLinus Torvalds t->control |= (T_RUN); 3284cdcdbe0bSLuiz Capitulino 32856146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32861da177e4SLinus Torvalds 328763adc6fbSStephen Hemminger /* Propagate thread->control */ 328863adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32891da177e4SLinus Torvalds 32901da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 32911da177e4SLinus Torvalds } 32921da177e4SLinus Torvalds 3293eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void) 3294eb37b41cSJesse Brandeburg { 3295eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3296eb37b41cSJesse Brandeburg 3297f9467eaeSJoe Perches func_enter(); 3298eb37b41cSJesse Brandeburg 3299eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3300eb37b41cSJesse Brandeburg 3301eb37b41cSJesse Brandeburg list_for_each_entry(t, &pktgen_threads, th_list) 3302eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3303eb37b41cSJesse Brandeburg 3304eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3305eb37b41cSJesse Brandeburg 330663adc6fbSStephen Hemminger /* Propagate thread->control */ 330763adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3308eb37b41cSJesse Brandeburg 3309eb37b41cSJesse Brandeburg pktgen_wait_all_threads_run(); 3310eb37b41cSJesse Brandeburg } 3311eb37b41cSJesse Brandeburg 33121da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 33131da177e4SLinus Torvalds { 3314fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 33151da177e4SLinus Torvalds char *p = pkt_dev->result; 3316fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3317fd29cf72SStephen Hemminger pkt_dev->started_at); 3318fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 33191da177e4SLinus Torvalds 3320fd29cf72SStephen Hemminger p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", 3321fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3322fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3323fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 33241da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 33251da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 33261da177e4SLinus Torvalds 3327fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3328fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 33291da177e4SLinus Torvalds 33301da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds mbps = bps; 33331da177e4SLinus Torvalds do_div(mbps, 1000000); 33341da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 33351da177e4SLinus Torvalds (unsigned long long)pps, 33361da177e4SLinus Torvalds (unsigned long long)mbps, 33371da177e4SLinus Torvalds (unsigned long long)bps, 33381da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 33391da177e4SLinus Torvalds } 33401da177e4SLinus Torvalds 33411da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 33421da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 33431da177e4SLinus Torvalds { 3344222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 33451da177e4SLinus Torvalds 33461da177e4SLinus Torvalds if (!pkt_dev->running) { 3347f9467eaeSJoe Perches pr_warning("interface: %s is already stopped\n", 3348f9467eaeSJoe Perches pkt_dev->odevname); 33491da177e4SLinus Torvalds return -EINVAL; 33501da177e4SLinus Torvalds } 33511da177e4SLinus Torvalds 33523bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 33533bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3354fd29cf72SStephen Hemminger pkt_dev->stopped_at = ktime_now(); 33551da177e4SLinus Torvalds pkt_dev->running = 0; 33561da177e4SLinus Torvalds 335795ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 33581da177e4SLinus Torvalds 33591da177e4SLinus Torvalds return 0; 33601da177e4SLinus Torvalds } 33611da177e4SLinus Torvalds 33621da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 33631da177e4SLinus Torvalds { 3364c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 33651da177e4SLinus Torvalds 33661da177e4SLinus Torvalds if_lock(t); 33671da177e4SLinus Torvalds 3368c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3369c26a8016SLuiz Capitulino if (!pkt_dev->running) 3370222f1806SLuiz Capitulino continue; 3371222f1806SLuiz Capitulino if (best == NULL) 3372c26a8016SLuiz Capitulino best = pkt_dev; 3373fd29cf72SStephen Hemminger else if (ktime_lt(pkt_dev->next_tx, best->next_tx)) 3374c26a8016SLuiz Capitulino best = pkt_dev; 33751da177e4SLinus Torvalds } 33761da177e4SLinus Torvalds if_unlock(t); 33771da177e4SLinus Torvalds return best; 33781da177e4SLinus Torvalds } 33791da177e4SLinus Torvalds 3380222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3381222f1806SLuiz Capitulino { 3382c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33831da177e4SLinus Torvalds 3384f9467eaeSJoe Perches func_enter(); 33851da177e4SLinus Torvalds 33861da177e4SLinus Torvalds if_lock(t); 33871da177e4SLinus Torvalds 3388c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3389c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 339095ed63f7SArthur Kepner } 339195ed63f7SArthur Kepner 339295ed63f7SArthur Kepner if_unlock(t); 339395ed63f7SArthur Kepner } 339495ed63f7SArthur Kepner 339595ed63f7SArthur Kepner /* 339695ed63f7SArthur Kepner * one of our devices needs to be removed - find it 339795ed63f7SArthur Kepner * and remove it 339895ed63f7SArthur Kepner */ 339995ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 340095ed63f7SArthur Kepner { 3401c26a8016SLuiz Capitulino struct list_head *q, *n; 3402c26a8016SLuiz Capitulino struct pktgen_dev *cur; 340395ed63f7SArthur Kepner 3404f9467eaeSJoe Perches func_enter(); 340595ed63f7SArthur Kepner 340695ed63f7SArthur Kepner if_lock(t); 340795ed63f7SArthur Kepner 3408c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3409c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 341095ed63f7SArthur Kepner 3411222f1806SLuiz Capitulino if (!cur->removal_mark) 3412222f1806SLuiz Capitulino continue; 341395ed63f7SArthur Kepner 341495ed63f7SArthur Kepner kfree_skb(cur->skb); 341595ed63f7SArthur Kepner cur->skb = NULL; 341695ed63f7SArthur Kepner 341795ed63f7SArthur Kepner pktgen_remove_device(t, cur); 341895ed63f7SArthur Kepner 341995ed63f7SArthur Kepner break; 342095ed63f7SArthur Kepner } 34211da177e4SLinus Torvalds 34221da177e4SLinus Torvalds if_unlock(t); 34231da177e4SLinus Torvalds } 34241da177e4SLinus Torvalds 34251da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 34261da177e4SLinus Torvalds { 3427c26a8016SLuiz Capitulino struct list_head *q, *n; 3428c26a8016SLuiz Capitulino struct pktgen_dev *cur; 34291da177e4SLinus Torvalds 3430f9467eaeSJoe Perches func_enter(); 3431f9467eaeSJoe Perches 34321da177e4SLinus Torvalds /* Remove all devices, free mem */ 34331da177e4SLinus Torvalds 34341da177e4SLinus Torvalds if_lock(t); 34351da177e4SLinus Torvalds 3436c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3437c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 343895ed63f7SArthur Kepner 343995ed63f7SArthur Kepner kfree_skb(cur->skb); 344095ed63f7SArthur Kepner cur->skb = NULL; 344195ed63f7SArthur Kepner 34421da177e4SLinus Torvalds pktgen_remove_device(t, cur); 34431da177e4SLinus Torvalds } 34441da177e4SLinus Torvalds 34451da177e4SLinus Torvalds if_unlock(t); 34461da177e4SLinus Torvalds } 34471da177e4SLinus Torvalds 34481da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 34491da177e4SLinus Torvalds { 34501da177e4SLinus Torvalds /* Remove from the thread list */ 34511da177e4SLinus Torvalds 3452ee74baa7SDavid S. Miller remove_proc_entry(t->tsk->comm, pg_proc_dir); 34531da177e4SLinus Torvalds 34546146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 34551da177e4SLinus Torvalds 3456cdcdbe0bSLuiz Capitulino list_del(&t->th_list); 3457cdcdbe0bSLuiz Capitulino 34586146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 34591da177e4SLinus Torvalds } 34601da177e4SLinus Torvalds 3461ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 34623791decbSStephen Hemminger { 3463fd29cf72SStephen Hemminger ktime_t idle_start = ktime_now(); 34643791decbSStephen Hemminger schedule(); 3465fd29cf72SStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 34663791decbSStephen Hemminger } 34673791decbSStephen Hemminger 3468ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3469ef87979cSStephen Hemminger { 3470ef87979cSStephen Hemminger ktime_t idle_start = ktime_now(); 3471ef87979cSStephen Hemminger 3472ef87979cSStephen Hemminger while (atomic_read(&(pkt_dev->skb->users)) != 1) { 3473ef87979cSStephen Hemminger if (signal_pending(current)) 3474ef87979cSStephen Hemminger break; 3475ef87979cSStephen Hemminger 3476ef87979cSStephen Hemminger if (need_resched()) 3477ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3478ef87979cSStephen Hemminger else 3479ef87979cSStephen Hemminger cpu_relax(); 3480ef87979cSStephen Hemminger } 3481ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 3482ef87979cSStephen Hemminger } 3483fd29cf72SStephen Hemminger 3484475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34851da177e4SLinus Torvalds { 348600829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 34876fef4c0cSStephen Hemminger netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *) 348800829823SStephen Hemminger = odev->netdev_ops->ndo_start_xmit; 3489fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 3490fd2ea0a7SDavid S. Miller u16 queue_map; 34911da177e4SLinus Torvalds int ret; 34921da177e4SLinus Torvalds 3493ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3494ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34951da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34963791decbSStephen Hemminger return; 34971da177e4SLinus Torvalds } 34981da177e4SLinus Torvalds 3499ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3500ef87979cSStephen Hemminger * "never transmit" 3501ef87979cSStephen Hemminger */ 3502ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3503ef87979cSStephen Hemminger pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); 3504ef87979cSStephen Hemminger return; 3505ef87979cSStephen Hemminger } 3506ef87979cSStephen Hemminger 3507ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 35087d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 35097d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 35101da177e4SLinus Torvalds /* build a new pkt */ 35111da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 35121da177e4SLinus Torvalds 35131da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 35141da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3515f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 35161da177e4SLinus Torvalds schedule(); 35171da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 35183791decbSStephen Hemminger return; 35191da177e4SLinus Torvalds } 3520baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 35211da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 35221da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 35231da177e4SLinus Torvalds } 35241da177e4SLinus Torvalds 3525ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3526ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3527ef87979cSStephen Hemminger 3528fd2ea0a7SDavid S. Miller queue_map = skb_get_queue_mapping(pkt_dev->skb); 3529fd2ea0a7SDavid S. Miller txq = netdev_get_tx_queue(odev, queue_map); 3530fd2ea0a7SDavid S. Miller 3531fd2ea0a7SDavid S. Miller __netif_tx_lock_bh(txq); 35325b8db2f5SStephen Hemminger 35330835acfeSEric Dumazet if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) { 3534ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 35350835acfeSEric Dumazet pkt_dev->last_ok = 0; 35360835acfeSEric Dumazet goto unlock; 35370835acfeSEric Dumazet } 35380835acfeSEric Dumazet atomic_inc(&(pkt_dev->skb->users)); 353900829823SStephen Hemminger ret = (*xmit)(pkt_dev->skb, odev); 3540ef87979cSStephen Hemminger 35415b8db2f5SStephen Hemminger switch (ret) { 35425b8db2f5SStephen Hemminger case NETDEV_TX_OK: 354308baf561SEric Dumazet txq_trans_update(txq); 35441da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35451da177e4SLinus Torvalds pkt_dev->sofar++; 35461da177e4SLinus Torvalds pkt_dev->seq_num++; 3547baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 35485b8db2f5SStephen Hemminger break; 3549f466dba1SJohn Fastabend case NET_XMIT_DROP: 3550f466dba1SJohn Fastabend case NET_XMIT_CN: 3551f466dba1SJohn Fastabend case NET_XMIT_POLICED: 3552f466dba1SJohn Fastabend /* skb has been consumed */ 3553f466dba1SJohn Fastabend pkt_dev->errors++; 3554f466dba1SJohn Fastabend break; 35555b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 35565b8db2f5SStephen Hemminger if (net_ratelimit()) 35575b8db2f5SStephen Hemminger pr_info("pktgen: %s xmit error: %d\n", 3558593f63b0SEric Dumazet pkt_dev->odevname, ret); 35591da177e4SLinus Torvalds pkt_dev->errors++; 35605b8db2f5SStephen Hemminger /* fallthru */ 3561ef87979cSStephen Hemminger case NETDEV_TX_LOCKED: 35625b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35635b8db2f5SStephen Hemminger /* Retry it next time */ 35645b8db2f5SStephen Hemminger atomic_dec(&(pkt_dev->skb->users)); 35651da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35661da177e4SLinus Torvalds } 35670835acfeSEric Dumazet unlock: 3568fd2ea0a7SDavid S. Miller __netif_tx_unlock_bh(txq); 35691da177e4SLinus Torvalds 35701da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35711da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3572ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35731da177e4SLinus Torvalds 35741da177e4SLinus Torvalds /* Done with this */ 35751da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35761da177e4SLinus Torvalds } 35771da177e4SLinus Torvalds } 35781da177e4SLinus Torvalds 35791da177e4SLinus Torvalds /* 35801da177e4SLinus Torvalds * Main loop of the thread goes here 35811da177e4SLinus Torvalds */ 35821da177e4SLinus Torvalds 3583ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 35841da177e4SLinus Torvalds { 35851da177e4SLinus Torvalds DEFINE_WAIT(wait); 3586ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 35871da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 35881da177e4SLinus Torvalds int cpu = t->cpu; 35891da177e4SLinus Torvalds 3590ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 35911da177e4SLinus Torvalds 35921da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3593d3ede327SDenis V. Lunev complete(&t->start_done); 35941da177e4SLinus Torvalds 3595f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 35961da177e4SLinus Torvalds 3597ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 35981da177e4SLinus Torvalds 359983144186SRafael J. Wysocki set_freezable(); 360083144186SRafael J. Wysocki 3601ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3602ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3603ee74baa7SDavid S. Miller 3604ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 3605ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3606ef87979cSStephen Hemminger t->control != 0, 3607ef87979cSStephen Hemminger HZ/10); 36081b3f720bSRafael J. Wysocki try_to_freeze(); 3609ef87979cSStephen Hemminger continue; 3610ee74baa7SDavid S. Miller } 36111da177e4SLinus Torvalds 36121da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 36131da177e4SLinus Torvalds 3614ef87979cSStephen Hemminger if (likely(pkt_dev)) { 36151da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 36161da177e4SLinus Torvalds 3617ef87979cSStephen Hemminger if (need_resched()) 3618ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3619ef87979cSStephen Hemminger else 3620ef87979cSStephen Hemminger cpu_relax(); 3621ef87979cSStephen Hemminger } 3622ef87979cSStephen Hemminger 36231da177e4SLinus Torvalds if (t->control & T_STOP) { 36241da177e4SLinus Torvalds pktgen_stop(t); 36251da177e4SLinus Torvalds t->control &= ~(T_STOP); 36261da177e4SLinus Torvalds } 36271da177e4SLinus Torvalds 36281da177e4SLinus Torvalds if (t->control & T_RUN) { 36291da177e4SLinus Torvalds pktgen_run(t); 36301da177e4SLinus Torvalds t->control &= ~(T_RUN); 36311da177e4SLinus Torvalds } 36321da177e4SLinus Torvalds 363395ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36341da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 363595ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 363695ed63f7SArthur Kepner } 363795ed63f7SArthur Kepner 363895ed63f7SArthur Kepner if (t->control & T_REMDEV) { 363995ed63f7SArthur Kepner pktgen_rem_one_if(t); 36401da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36411da177e4SLinus Torvalds } 36421da177e4SLinus Torvalds 364309fe3ef4SAndrew Morton try_to_freeze(); 364409fe3ef4SAndrew Morton 3645ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 36461da177e4SLinus Torvalds } 36471da177e4SLinus Torvalds 3648f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36491da177e4SLinus Torvalds pktgen_stop(t); 36501da177e4SLinus Torvalds 3651f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36521da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36531da177e4SLinus Torvalds 3654f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36551da177e4SLinus Torvalds pktgen_rem_thread(t); 3656cdcdbe0bSLuiz Capitulino 3657ee74baa7SDavid S. Miller return 0; 36581da177e4SLinus Torvalds } 36591da177e4SLinus Torvalds 3660222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36613e984840SEric Dumazet const char *ifname, bool exact) 36621da177e4SLinus Torvalds { 3663c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36643e984840SEric Dumazet size_t len = strlen(ifname); 36651da177e4SLinus Torvalds 36663e984840SEric Dumazet if_lock(t); 3667c26a8016SLuiz Capitulino list_for_each_entry(p, &t->if_list, list) 36683e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36693e984840SEric Dumazet if (p->odevname[len]) { 36703e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36713e984840SEric Dumazet continue; 36723e984840SEric Dumazet } 3673c26a8016SLuiz Capitulino pkt_dev = p; 36741da177e4SLinus Torvalds break; 36751da177e4SLinus Torvalds } 36761da177e4SLinus Torvalds 36771da177e4SLinus Torvalds if_unlock(t); 3678f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36791da177e4SLinus Torvalds return pkt_dev; 36801da177e4SLinus Torvalds } 36811da177e4SLinus Torvalds 36821da177e4SLinus Torvalds /* 36831da177e4SLinus Torvalds * Adds a dev at front of if_list. 36841da177e4SLinus Torvalds */ 36851da177e4SLinus Torvalds 3686222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3687222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36881da177e4SLinus Torvalds { 36891da177e4SLinus Torvalds int rv = 0; 36901da177e4SLinus Torvalds 36911da177e4SLinus Torvalds if_lock(t); 36921da177e4SLinus Torvalds 36931da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3694f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 36951da177e4SLinus Torvalds rv = -EBUSY; 36961da177e4SLinus Torvalds goto out; 36971da177e4SLinus Torvalds } 3698c26a8016SLuiz Capitulino 3699c26a8016SLuiz Capitulino list_add(&pkt_dev->list, &t->if_list); 37001da177e4SLinus Torvalds pkt_dev->pg_thread = t; 37011da177e4SLinus Torvalds pkt_dev->running = 0; 37021da177e4SLinus Torvalds 37031da177e4SLinus Torvalds out: 37041da177e4SLinus Torvalds if_unlock(t); 37051da177e4SLinus Torvalds return rv; 37061da177e4SLinus Torvalds } 37071da177e4SLinus Torvalds 37081da177e4SLinus Torvalds /* Called under thread lock */ 37091da177e4SLinus Torvalds 37101da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 37111da177e4SLinus Torvalds { 37121da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 371339df232fSStephen Hemminger int err; 37143291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 37151da177e4SLinus Torvalds 37161da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 37171da177e4SLinus Torvalds 3718d50a6b56SStephen Hemminger pkt_dev = __pktgen_NN_threads(ifname, FIND); 3719d50a6b56SStephen Hemminger if (pkt_dev) { 3720f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3721d50a6b56SStephen Hemminger return -EBUSY; 3722d50a6b56SStephen Hemminger } 37231da177e4SLinus Torvalds 37243291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37251da177e4SLinus Torvalds if (!pkt_dev) 37261da177e4SLinus Torvalds return -ENOMEM; 37271da177e4SLinus Torvalds 3728593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 37293291b9dbSEric Dumazet pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 37303291b9dbSEric Dumazet node); 37311da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37321da177e4SLinus Torvalds kfree(pkt_dev); 37331da177e4SLinus Torvalds return -ENOMEM; 37341da177e4SLinus Torvalds } 37351da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); 37361da177e4SLinus Torvalds 373795ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37381da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 37391da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 37401da177e4SLinus Torvalds pkt_dev->nfrags = 0; 37411da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 3742fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37431da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37441da177e4SLinus Torvalds pkt_dev->sofar = 0; 37451da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37461da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37471da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37481da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 37491da177e4SLinus Torvalds 375034954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 375134954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 375234954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 375334954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 375434954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 375534954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 3756e99b99b4SRobert Olsson pkt_dev->node = -1; 375734954ddcSFrancesco Fondelli 375839df232fSStephen Hemminger err = pktgen_setup_dev(pkt_dev, ifname); 375939df232fSStephen Hemminger if (err) 376039df232fSStephen Hemminger goto out1; 37611da177e4SLinus Torvalds 37625efdccbcSDenis V. Lunev pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir, 37635efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 376439df232fSStephen Hemminger if (!pkt_dev->entry) { 3765f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3766d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 376739df232fSStephen Hemminger err = -EINVAL; 376839df232fSStephen Hemminger goto out2; 376939df232fSStephen Hemminger } 3770a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3771a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3772a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3773a553e4a6SJamal Hadi Salim #endif 377439df232fSStephen Hemminger 377539df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 377639df232fSStephen Hemminger out2: 377739df232fSStephen Hemminger dev_put(pkt_dev->odev); 377839df232fSStephen Hemminger out1: 3779a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3780a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3781a553e4a6SJamal Hadi Salim #endif 37821da177e4SLinus Torvalds vfree(pkt_dev->flows); 37831da177e4SLinus Torvalds kfree(pkt_dev); 378439df232fSStephen Hemminger return err; 37851da177e4SLinus Torvalds } 37861da177e4SLinus Torvalds 3787ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu) 37881da177e4SLinus Torvalds { 3789cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3790d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3791ee74baa7SDavid S. Miller struct task_struct *p; 37921da177e4SLinus Torvalds 37933291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 37943291b9dbSEric Dumazet cpu_to_node(cpu)); 37951da177e4SLinus Torvalds if (!t) { 3796f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 37971da177e4SLinus Torvalds return -ENOMEM; 37981da177e4SLinus Torvalds } 37991da177e4SLinus Torvalds 38001da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 38011da177e4SLinus Torvalds t->cpu = cpu; 38021da177e4SLinus Torvalds 3803ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3804ee74baa7SDavid S. Miller 3805ee74baa7SDavid S. Miller list_add_tail(&t->th_list, &pktgen_threads); 3806d3ede327SDenis V. Lunev init_completion(&t->start_done); 3807ee74baa7SDavid S. Miller 3808ee74baa7SDavid S. Miller p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); 3809ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3810f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3811ee74baa7SDavid S. Miller list_del(&t->th_list); 3812ee74baa7SDavid S. Miller kfree(t); 3813ee74baa7SDavid S. Miller return PTR_ERR(p); 3814ee74baa7SDavid S. Miller } 3815ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3816ee74baa7SDavid S. Miller t->tsk = p; 3817ee74baa7SDavid S. Miller 38185efdccbcSDenis V. Lunev pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir, 38195efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3820d50a6b56SStephen Hemminger if (!pe) { 3821f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3822ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3823ee74baa7SDavid S. Miller kthread_stop(p); 3824ee74baa7SDavid S. Miller list_del(&t->th_list); 38251da177e4SLinus Torvalds kfree(t); 38261da177e4SLinus Torvalds return -EINVAL; 38271da177e4SLinus Torvalds } 3828d50a6b56SStephen Hemminger 3829ee74baa7SDavid S. Miller wake_up_process(p); 3830d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38311da177e4SLinus Torvalds 38321da177e4SLinus Torvalds return 0; 38331da177e4SLinus Torvalds } 38341da177e4SLinus Torvalds 38351da177e4SLinus Torvalds /* 38361da177e4SLinus Torvalds * Removes a device from the thread if_list. 38371da177e4SLinus Torvalds */ 3838222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3839222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38401da177e4SLinus Torvalds { 3841c26a8016SLuiz Capitulino struct list_head *q, *n; 3842c26a8016SLuiz Capitulino struct pktgen_dev *p; 38431da177e4SLinus Torvalds 3844c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3845c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3846c26a8016SLuiz Capitulino if (p == pkt_dev) 3847c26a8016SLuiz Capitulino list_del(&p->list); 38481da177e4SLinus Torvalds } 38491da177e4SLinus Torvalds } 38501da177e4SLinus Torvalds 3851222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3852222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38531da177e4SLinus Torvalds { 38541da177e4SLinus Torvalds 3855f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38561da177e4SLinus Torvalds 38571da177e4SLinus Torvalds if (pkt_dev->running) { 3858f9467eaeSJoe Perches pr_warning("WARNING: trying to remove a running interface, stopping it now\n"); 38591da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38601da177e4SLinus Torvalds } 38611da177e4SLinus Torvalds 38621da177e4SLinus Torvalds /* Dis-associate from the interface */ 38631da177e4SLinus Torvalds 38641da177e4SLinus Torvalds if (pkt_dev->odev) { 38651da177e4SLinus Torvalds dev_put(pkt_dev->odev); 38661da177e4SLinus Torvalds pkt_dev->odev = NULL; 38671da177e4SLinus Torvalds } 38681da177e4SLinus Torvalds 38691da177e4SLinus Torvalds /* And update the thread if_list */ 38701da177e4SLinus Torvalds 38711da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 38721da177e4SLinus Torvalds 387339df232fSStephen Hemminger if (pkt_dev->entry) 387439df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 38751da177e4SLinus Torvalds 3876a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3877a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3878a553e4a6SJamal Hadi Salim #endif 38791da177e4SLinus Torvalds vfree(pkt_dev->flows); 38801da177e4SLinus Torvalds kfree(pkt_dev); 38811da177e4SLinus Torvalds return 0; 38821da177e4SLinus Torvalds } 38831da177e4SLinus Torvalds 38841da177e4SLinus Torvalds static int __init pg_init(void) 38851da177e4SLinus Torvalds { 38861da177e4SLinus Torvalds int cpu; 3887d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3888d50a6b56SStephen Hemminger 3889f9467eaeSJoe Perches pr_info("%s", version); 38901da177e4SLinus Torvalds 3891457c4cbcSEric W. Biederman pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); 3892d50a6b56SStephen Hemminger if (!pg_proc_dir) 3893d50a6b56SStephen Hemminger return -ENODEV; 38941da177e4SLinus Torvalds 389525296d59SWang Chen pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); 3896d50a6b56SStephen Hemminger if (pe == NULL) { 3897f9467eaeSJoe Perches pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); 3898457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 38991da177e4SLinus Torvalds return -EINVAL; 39001da177e4SLinus Torvalds } 39011da177e4SLinus Torvalds 39021da177e4SLinus Torvalds /* Register us to receive netdevice events */ 39031da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 39041da177e4SLinus Torvalds 3905670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 39068024bb24SLuiz Capitulino int err; 39071da177e4SLinus Torvalds 3908ee74baa7SDavid S. Miller err = pktgen_create_thread(cpu); 39098024bb24SLuiz Capitulino if (err) 3910f9467eaeSJoe Perches pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n", 3911f9467eaeSJoe Perches cpu, err); 39121da177e4SLinus Torvalds } 39138024bb24SLuiz Capitulino 39148024bb24SLuiz Capitulino if (list_empty(&pktgen_threads)) { 3915f9467eaeSJoe Perches pr_err("ERROR: Initialization failed for all threads\n"); 39168024bb24SLuiz Capitulino unregister_netdevice_notifier(&pktgen_notifier_block); 39178024bb24SLuiz Capitulino remove_proc_entry(PGCTRL, pg_proc_dir); 3918457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39198024bb24SLuiz Capitulino return -ENODEV; 39208024bb24SLuiz Capitulino } 39218024bb24SLuiz Capitulino 39221da177e4SLinus Torvalds return 0; 39231da177e4SLinus Torvalds } 39241da177e4SLinus Torvalds 39251da177e4SLinus Torvalds static void __exit pg_cleanup(void) 39261da177e4SLinus Torvalds { 3927cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3928cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 39291da177e4SLinus Torvalds 39301da177e4SLinus Torvalds /* Stop all interfaces & threads */ 39311da177e4SLinus Torvalds 3932cdcdbe0bSLuiz Capitulino list_for_each_safe(q, n, &pktgen_threads) { 3933cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3934ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3935ee74baa7SDavid S. Miller kfree(t); 39361da177e4SLinus Torvalds } 39371da177e4SLinus Torvalds 39381da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 39391da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 39401da177e4SLinus Torvalds 39411da177e4SLinus Torvalds /* Clean up proc file system */ 3942d50a6b56SStephen Hemminger remove_proc_entry(PGCTRL, pg_proc_dir); 3943457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39441da177e4SLinus Torvalds } 39451da177e4SLinus Torvalds 39461da177e4SLinus Torvalds module_init(pg_init); 39471da177e4SLinus Torvalds module_exit(pg_cleanup); 39481da177e4SLinus Torvalds 3949c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 39501da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 39511da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3952c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 39531da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3954c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 39551da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3956c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 39571da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3958c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 39591da177e4SLinus Torvalds module_param(debug, int, 0); 3960c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3961