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; 3819e50e3acSJohn 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 398551eaff1SEric Dumazet static bool pktgen_exiting __read_mostly; 399551eaff1SEric Dumazet 4001da177e4SLinus Torvalds struct pktgen_thread { 40163adc6fbSStephen Hemminger spinlock_t if_lock; /* for list of devices */ 402c26a8016SLuiz Capitulino struct list_head if_list; /* All device here */ 403cdcdbe0bSLuiz Capitulino struct list_head th_list; 404ee74baa7SDavid S. Miller struct task_struct *tsk; 4051da177e4SLinus Torvalds char result[512]; 4061da177e4SLinus Torvalds 40763adc6fbSStephen Hemminger /* Field for thread to receive "posted" events terminate, 40863adc6fbSStephen Hemminger stop ifs etc. */ 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds u32 control; 4111da177e4SLinus Torvalds int cpu; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds wait_queue_head_t queue; 414d3ede327SDenis V. Lunev struct completion start_done; 4151da177e4SLinus Torvalds }; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds #define REMOVE 1 4181da177e4SLinus Torvalds #define FIND 0 4191da177e4SLinus Torvalds 420fd29cf72SStephen Hemminger static inline ktime_t ktime_now(void) 4211da177e4SLinus Torvalds { 422fd29cf72SStephen Hemminger struct timespec ts; 423fd29cf72SStephen Hemminger ktime_get_ts(&ts); 424fd29cf72SStephen Hemminger 425fd29cf72SStephen Hemminger return timespec_to_ktime(ts); 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 428fd29cf72SStephen Hemminger /* This works even if 32 bit because of careful byte order choice */ 429fd29cf72SStephen Hemminger static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2) 4301da177e4SLinus Torvalds { 431fd29cf72SStephen Hemminger return cmp1.tv64 < cmp2.tv64; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 434c3d2f52dSStephen Hemminger static const char version[] = 435f9467eaeSJoe Perches "Packet Generator for packet performance testing. " 436f9467eaeSJoe Perches "Version: " VERSION "\n"; 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); 4391da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); 440222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 4413e984840SEric Dumazet const char *ifname, bool exact); 4421da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *); 4431da177e4SLinus Torvalds static void pktgen_run_all_threads(void); 444eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void); 4451da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void); 4463bda06a3SStephen Hemminger 4471da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t); 4481da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); 44939df232fSStephen Hemminger 4501da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]); 4511da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s, const char ip[16]); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* Module parameters, defaults. */ 45465c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000; 45565c5b786SStephen Hemminger static int pg_delay_d __read_mostly; 45665c5b786SStephen Hemminger static int pg_clone_skb_d __read_mostly; 45765c5b786SStephen Hemminger static int debug __read_mostly; 4581da177e4SLinus Torvalds 459222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock); 460cdcdbe0bSLuiz Capitulino static LIST_HEAD(pktgen_threads); 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = { 4631da177e4SLinus Torvalds .notifier_call = pktgen_device_event, 4641da177e4SLinus Torvalds }; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds /* 4671da177e4SLinus Torvalds * /proc handling functions 4681da177e4SLinus Torvalds * 4691da177e4SLinus Torvalds */ 4701da177e4SLinus Torvalds 471d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v) 472d50a6b56SStephen Hemminger { 473c3d2f52dSStephen Hemminger seq_puts(seq, version); 474d50a6b56SStephen Hemminger return 0; 475d50a6b56SStephen Hemminger } 4761da177e4SLinus Torvalds 477d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf, 4781da177e4SLinus Torvalds size_t count, loff_t *ppos) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds int err = 0; 481d50a6b56SStephen Hemminger char data[128]; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) { 4841da177e4SLinus Torvalds err = -EPERM; 4851da177e4SLinus Torvalds goto out; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 488d50a6b56SStephen Hemminger if (count > sizeof(data)) 489d50a6b56SStephen Hemminger count = sizeof(data); 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds if (copy_from_user(data, buf, count)) { 4921da177e4SLinus Torvalds err = -EFAULT; 493d50a6b56SStephen Hemminger goto out; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds data[count - 1] = 0; /* Make string */ 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds if (!strcmp(data, "stop")) 4981da177e4SLinus Torvalds pktgen_stop_all_threads_ifs(); 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds else if (!strcmp(data, "start")) 5011da177e4SLinus Torvalds pktgen_run_all_threads(); 5021da177e4SLinus Torvalds 503eb37b41cSJesse Brandeburg else if (!strcmp(data, "reset")) 504eb37b41cSJesse Brandeburg pktgen_reset_all_threads(); 505eb37b41cSJesse Brandeburg 5061da177e4SLinus Torvalds else 507f9467eaeSJoe Perches pr_warning("Unknown command: %s\n", data); 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds err = count; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds out: 5121da177e4SLinus Torvalds return err; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 515d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file) 5161da177e4SLinus Torvalds { 517d50a6b56SStephen Hemminger return single_open(file, pgctrl_show, PDE(inode)->data); 518d50a6b56SStephen Hemminger } 519d50a6b56SStephen Hemminger 5209a32144eSArjan van de Ven static const struct file_operations pktgen_fops = { 521d50a6b56SStephen Hemminger .owner = THIS_MODULE, 522d50a6b56SStephen Hemminger .open = pgctrl_open, 523d50a6b56SStephen Hemminger .read = seq_read, 524d50a6b56SStephen Hemminger .llseek = seq_lseek, 525d50a6b56SStephen Hemminger .write = pgctrl_write, 526d50a6b56SStephen Hemminger .release = single_release, 527d50a6b56SStephen Hemminger }; 528d50a6b56SStephen Hemminger 529d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v) 530d50a6b56SStephen Hemminger { 531648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev = seq->private; 532fd29cf72SStephen Hemminger ktime_t stopped; 533fd29cf72SStephen Hemminger u64 idle; 5341da177e4SLinus Torvalds 535222f1806SLuiz Capitulino seq_printf(seq, 536222f1806SLuiz Capitulino "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", 537222f1806SLuiz Capitulino (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, 538222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 5391da177e4SLinus Torvalds 540222f1806SLuiz Capitulino seq_printf(seq, 541fd29cf72SStephen Hemminger " frags: %d delay: %llu clone_skb: %d ifname: %s\n", 542fd29cf72SStephen Hemminger pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, 543593f63b0SEric Dumazet pkt_dev->clone_skb, pkt_dev->odevname); 5441da177e4SLinus Torvalds 545222f1806SLuiz Capitulino seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, 546222f1806SLuiz Capitulino pkt_dev->lflow); 5471da177e4SLinus Torvalds 54845b270f8SRobert Olsson seq_printf(seq, 54945b270f8SRobert Olsson " queue_map_min: %u queue_map_max: %u\n", 55045b270f8SRobert Olsson pkt_dev->queue_map_min, 55145b270f8SRobert Olsson pkt_dev->queue_map_max); 55245b270f8SRobert Olsson 5539e50e3acSJohn Fastabend if (pkt_dev->skb_priority) 5549e50e3acSJohn Fastabend seq_printf(seq, " skb_priority: %u\n", 5559e50e3acSJohn Fastabend pkt_dev->skb_priority); 5569e50e3acSJohn Fastabend 5571da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 5581da177e4SLinus Torvalds char b1[128], b2[128], b3[128]; 5591da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); 5601da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); 5611da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); 562222f1806SLuiz Capitulino seq_printf(seq, 563222f1806SLuiz Capitulino " saddr: %s min_saddr: %s max_saddr: %s\n", b1, 564222f1806SLuiz Capitulino b2, b3); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); 5671da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); 5681da177e4SLinus Torvalds fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); 569222f1806SLuiz Capitulino seq_printf(seq, 570222f1806SLuiz Capitulino " daddr: %s min_daddr: %s max_daddr: %s\n", b1, 571222f1806SLuiz Capitulino b2, b3); 5721da177e4SLinus Torvalds 57363adc6fbSStephen Hemminger } else { 574222f1806SLuiz Capitulino seq_printf(seq, 57563adc6fbSStephen Hemminger " dst_min: %s dst_max: %s\n", 57663adc6fbSStephen Hemminger pkt_dev->dst_min, pkt_dev->dst_max); 57763adc6fbSStephen Hemminger seq_printf(seq, 57863adc6fbSStephen Hemminger " src_min: %s src_max: %s\n", 57963adc6fbSStephen Hemminger pkt_dev->src_min, pkt_dev->src_max); 58063adc6fbSStephen Hemminger } 5811da177e4SLinus Torvalds 582d50a6b56SStephen Hemminger seq_puts(seq, " src_mac: "); 5831da177e4SLinus Torvalds 584e174961cSJohannes Berg seq_printf(seq, "%pM ", 585e174961cSJohannes Berg is_zero_ether_addr(pkt_dev->src_mac) ? 586e174961cSJohannes Berg pkt_dev->odev->dev_addr : pkt_dev->src_mac); 5871da177e4SLinus Torvalds 588d50a6b56SStephen Hemminger seq_printf(seq, "dst_mac: "); 589e174961cSJohannes Berg seq_printf(seq, "%pM\n", pkt_dev->dst_mac); 5901da177e4SLinus Torvalds 591222f1806SLuiz Capitulino seq_printf(seq, 59263adc6fbSStephen Hemminger " udp_src_min: %d udp_src_max: %d" 59363adc6fbSStephen Hemminger " udp_dst_min: %d udp_dst_max: %d\n", 594222f1806SLuiz Capitulino pkt_dev->udp_src_min, pkt_dev->udp_src_max, 595222f1806SLuiz Capitulino pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); 5961da177e4SLinus Torvalds 597222f1806SLuiz Capitulino seq_printf(seq, 598ca6549afSSteven Whitehouse " src_mac_count: %d dst_mac_count: %d\n", 5991da177e4SLinus Torvalds pkt_dev->src_mac_count, pkt_dev->dst_mac_count); 6001da177e4SLinus Torvalds 601ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) { 602ca6549afSSteven Whitehouse unsigned i; 603ca6549afSSteven Whitehouse seq_printf(seq, " mpls: "); 604ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 605ca6549afSSteven Whitehouse seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), 606ca6549afSSteven Whitehouse i == pkt_dev->nr_labels-1 ? "\n" : ", "); 607ca6549afSSteven Whitehouse } 608ca6549afSSteven Whitehouse 60963adc6fbSStephen Hemminger if (pkt_dev->vlan_id != 0xffff) 61034954ddcSFrancesco Fondelli seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n", 61163adc6fbSStephen Hemminger pkt_dev->vlan_id, pkt_dev->vlan_p, 61263adc6fbSStephen Hemminger pkt_dev->vlan_cfi); 61334954ddcSFrancesco Fondelli 61463adc6fbSStephen Hemminger if (pkt_dev->svlan_id != 0xffff) 61534954ddcSFrancesco Fondelli seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n", 61663adc6fbSStephen Hemminger pkt_dev->svlan_id, pkt_dev->svlan_p, 61763adc6fbSStephen Hemminger pkt_dev->svlan_cfi); 61834954ddcSFrancesco Fondelli 61963adc6fbSStephen Hemminger if (pkt_dev->tos) 6201ca7768cSFrancesco Fondelli seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos); 6211ca7768cSFrancesco Fondelli 62263adc6fbSStephen Hemminger if (pkt_dev->traffic_class) 6231ca7768cSFrancesco Fondelli seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 6241ca7768cSFrancesco Fondelli 625e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 626e99b99b4SRobert Olsson seq_printf(seq, " node: %d\n", pkt_dev->node); 627e99b99b4SRobert Olsson 628ca6549afSSteven Whitehouse seq_printf(seq, " Flags: "); 629ca6549afSSteven Whitehouse 6301da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 631d50a6b56SStephen Hemminger seq_printf(seq, "IPV6 "); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 634d50a6b56SStephen Hemminger seq_printf(seq, "IPSRC_RND "); 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) 637d50a6b56SStephen Hemminger seq_printf(seq, "IPDST_RND "); 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) 640d50a6b56SStephen Hemminger seq_printf(seq, "TXSIZE_RND "); 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 643d50a6b56SStephen Hemminger seq_printf(seq, "UDPSRC_RND "); 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) 646d50a6b56SStephen Hemminger seq_printf(seq, "UDPDST_RND "); 6471da177e4SLinus Torvalds 648ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) 649ca6549afSSteven Whitehouse seq_printf(seq, "MPLS_RND "); 650ca6549afSSteven Whitehouse 65145b270f8SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_RND) 65245b270f8SRobert Olsson seq_printf(seq, "QUEUE_MAP_RND "); 65345b270f8SRobert Olsson 654e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 655e6fce5b9SRobert Olsson seq_printf(seq, "QUEUE_MAP_CPU "); 656e6fce5b9SRobert Olsson 657007a531bSJamal Hadi Salim if (pkt_dev->cflows) { 658007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) 659007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/ 660007a531bSJamal Hadi Salim else 661007a531bSJamal Hadi Salim seq_printf(seq, "FLOW_RND "); 662007a531bSJamal Hadi Salim } 663007a531bSJamal Hadi Salim 664a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 665a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 666a553e4a6SJamal Hadi Salim seq_printf(seq, "IPSEC "); 667a553e4a6SJamal Hadi Salim #endif 668a553e4a6SJamal Hadi Salim 6691da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 670d50a6b56SStephen Hemminger seq_printf(seq, "MACSRC_RND "); 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 673d50a6b56SStephen Hemminger seq_printf(seq, "MACDST_RND "); 6741da177e4SLinus Torvalds 67534954ddcSFrancesco Fondelli if (pkt_dev->flags & F_VID_RND) 67634954ddcSFrancesco Fondelli seq_printf(seq, "VID_RND "); 67734954ddcSFrancesco Fondelli 67834954ddcSFrancesco Fondelli if (pkt_dev->flags & F_SVID_RND) 67934954ddcSFrancesco Fondelli seq_printf(seq, "SVID_RND "); 68034954ddcSFrancesco Fondelli 681e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) 682e99b99b4SRobert Olsson seq_printf(seq, "NODE_ALLOC "); 683e99b99b4SRobert Olsson 684d50a6b56SStephen Hemminger seq_puts(seq, "\n"); 6851da177e4SLinus Torvalds 686fd29cf72SStephen Hemminger /* not really stopped, more like last-running-at */ 687fd29cf72SStephen Hemminger stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at; 688fd29cf72SStephen Hemminger idle = pkt_dev->idle_acc; 689fd29cf72SStephen Hemminger do_div(idle, NSEC_PER_USEC); 6901da177e4SLinus Torvalds 691222f1806SLuiz Capitulino seq_printf(seq, 692fd29cf72SStephen Hemminger "Current:\n pkts-sofar: %llu errors: %llu\n", 6931da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 694fd29cf72SStephen Hemminger (unsigned long long)pkt_dev->errors); 695fd29cf72SStephen Hemminger 696fd29cf72SStephen Hemminger seq_printf(seq, 697fd29cf72SStephen Hemminger " started: %lluus stopped: %lluus idle: %lluus\n", 698fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(pkt_dev->started_at), 699fd29cf72SStephen Hemminger (unsigned long long) ktime_to_us(stopped), 700fd29cf72SStephen Hemminger (unsigned long long) idle); 7011da177e4SLinus Torvalds 702222f1806SLuiz Capitulino seq_printf(seq, 703222f1806SLuiz Capitulino " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", 704d50a6b56SStephen Hemminger pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, 705d50a6b56SStephen Hemminger pkt_dev->cur_src_mac_offset); 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 7081da177e4SLinus Torvalds char b1[128], b2[128]; 7091da177e4SLinus Torvalds fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); 7101da177e4SLinus Torvalds fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); 711d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); 712222f1806SLuiz Capitulino } else 713d50a6b56SStephen Hemminger seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", 7141da177e4SLinus Torvalds pkt_dev->cur_saddr, pkt_dev->cur_daddr); 7151da177e4SLinus Torvalds 716d50a6b56SStephen Hemminger seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", 7171da177e4SLinus Torvalds pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); 7181da177e4SLinus Torvalds 71945b270f8SRobert Olsson seq_printf(seq, " cur_queue_map: %u\n", pkt_dev->cur_queue_map); 72045b270f8SRobert Olsson 721d50a6b56SStephen Hemminger seq_printf(seq, " flows: %u\n", pkt_dev->nflows); 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds if (pkt_dev->result[0]) 724d50a6b56SStephen Hemminger seq_printf(seq, "Result: %s\n", pkt_dev->result); 7251da177e4SLinus Torvalds else 726d50a6b56SStephen Hemminger seq_printf(seq, "Result: Idle\n"); 7271da177e4SLinus Torvalds 728d50a6b56SStephen Hemminger return 0; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds 731ca6549afSSteven Whitehouse 73263adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, 73363adc6fbSStephen Hemminger __u32 *num) 734ca6549afSSteven Whitehouse { 735ca6549afSSteven Whitehouse int i = 0; 736ca6549afSSteven Whitehouse *num = 0; 737ca6549afSSteven Whitehouse 7381ca7768cSFrancesco Fondelli for (; i < maxlen; i++) { 73982fd5b5dSAndy Shevchenko int value; 740ca6549afSSteven Whitehouse char c; 741ca6549afSSteven Whitehouse *num <<= 4; 742ca6549afSSteven Whitehouse if (get_user(c, &user_buffer[i])) 743ca6549afSSteven Whitehouse return -EFAULT; 74482fd5b5dSAndy Shevchenko value = hex_to_bin(c); 74582fd5b5dSAndy Shevchenko if (value >= 0) 74682fd5b5dSAndy Shevchenko *num |= value; 747ca6549afSSteven Whitehouse else 748ca6549afSSteven Whitehouse break; 749ca6549afSSteven Whitehouse } 750ca6549afSSteven Whitehouse return i; 751ca6549afSSteven Whitehouse } 752ca6549afSSteven Whitehouse 753222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer, 754222f1806SLuiz Capitulino unsigned int maxlen) 7551da177e4SLinus Torvalds { 7561da177e4SLinus Torvalds int i; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds for (i = 0; i < maxlen; i++) { 7591da177e4SLinus Torvalds char c; 7601da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7611da177e4SLinus Torvalds return -EFAULT; 7621da177e4SLinus Torvalds switch (c) { 7631da177e4SLinus Torvalds case '\"': 7641da177e4SLinus Torvalds case '\n': 7651da177e4SLinus Torvalds case '\r': 7661da177e4SLinus Torvalds case '\t': 7671da177e4SLinus Torvalds case ' ': 7681da177e4SLinus Torvalds case '=': 7691da177e4SLinus Torvalds break; 7701da177e4SLinus Torvalds default: 7711da177e4SLinus Torvalds goto done; 7723ff50b79SStephen Hemminger } 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds done: 7751da177e4SLinus Torvalds return i; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 778222f1806SLuiz Capitulino static unsigned long num_arg(const char __user * user_buffer, 779222f1806SLuiz Capitulino unsigned long maxlen, unsigned long *num) 7801da177e4SLinus Torvalds { 781d6182223SPaul Gortmaker int i; 7821da177e4SLinus Torvalds *num = 0; 7831da177e4SLinus Torvalds 784d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 7851da177e4SLinus Torvalds char c; 7861da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 7871da177e4SLinus Torvalds return -EFAULT; 7881da177e4SLinus Torvalds if ((c >= '0') && (c <= '9')) { 7891da177e4SLinus Torvalds *num *= 10; 7901da177e4SLinus Torvalds *num += c - '0'; 7911da177e4SLinus Torvalds } else 7921da177e4SLinus Torvalds break; 7931da177e4SLinus Torvalds } 7941da177e4SLinus Torvalds return i; 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen) 7981da177e4SLinus Torvalds { 799d6182223SPaul Gortmaker int i; 8001da177e4SLinus Torvalds 801d6182223SPaul Gortmaker for (i = 0; i < maxlen; i++) { 8021da177e4SLinus Torvalds char c; 8031da177e4SLinus Torvalds if (get_user(c, &user_buffer[i])) 8041da177e4SLinus Torvalds return -EFAULT; 8051da177e4SLinus Torvalds switch (c) { 8061da177e4SLinus Torvalds case '\"': 8071da177e4SLinus Torvalds case '\n': 8081da177e4SLinus Torvalds case '\r': 8091da177e4SLinus Torvalds case '\t': 8101da177e4SLinus Torvalds case ' ': 8111da177e4SLinus Torvalds goto done_str; 8121da177e4SLinus Torvalds break; 8131da177e4SLinus Torvalds default: 8141da177e4SLinus Torvalds break; 8153ff50b79SStephen Hemminger } 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds done_str: 8181da177e4SLinus Torvalds return i; 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds 821ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) 822ca6549afSSteven Whitehouse { 823ca6549afSSteven Whitehouse unsigned n = 0; 824ca6549afSSteven Whitehouse char c; 825ca6549afSSteven Whitehouse ssize_t i = 0; 826ca6549afSSteven Whitehouse int len; 827ca6549afSSteven Whitehouse 828ca6549afSSteven Whitehouse pkt_dev->nr_labels = 0; 829ca6549afSSteven Whitehouse do { 830ca6549afSSteven Whitehouse __u32 tmp; 8311ca7768cSFrancesco Fondelli len = hex32_arg(&buffer[i], 8, &tmp); 832ca6549afSSteven Whitehouse if (len <= 0) 833ca6549afSSteven Whitehouse return len; 834ca6549afSSteven Whitehouse pkt_dev->labels[n] = htonl(tmp); 835ca6549afSSteven Whitehouse if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) 836ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 837ca6549afSSteven Whitehouse i += len; 838ca6549afSSteven Whitehouse if (get_user(c, &buffer[i])) 839ca6549afSSteven Whitehouse return -EFAULT; 840ca6549afSSteven Whitehouse i++; 841ca6549afSSteven Whitehouse n++; 842ca6549afSSteven Whitehouse if (n >= MAX_MPLS_LABELS) 843ca6549afSSteven Whitehouse return -E2BIG; 844ca6549afSSteven Whitehouse } while (c == ','); 845ca6549afSSteven Whitehouse 846ca6549afSSteven Whitehouse pkt_dev->nr_labels = n; 847ca6549afSSteven Whitehouse return i; 848ca6549afSSteven Whitehouse } 849ca6549afSSteven Whitehouse 850222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file, 851222f1806SLuiz Capitulino const char __user * user_buffer, size_t count, 852222f1806SLuiz Capitulino loff_t * offset) 8531da177e4SLinus Torvalds { 8548a994a71SJoe Perches struct seq_file *seq = file->private_data; 855d50a6b56SStephen Hemminger struct pktgen_dev *pkt_dev = seq->private; 856d6182223SPaul Gortmaker int i, max, len; 8571da177e4SLinus Torvalds char name[16], valstr[32]; 8581da177e4SLinus Torvalds unsigned long value = 0; 8591da177e4SLinus Torvalds char *pg_result = NULL; 8601da177e4SLinus Torvalds int tmp = 0; 8611da177e4SLinus Torvalds char buf[128]; 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds pg_result = &(pkt_dev->result[0]); 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds if (count < 1) { 866f9467eaeSJoe Perches pr_warning("wrong command format\n"); 8671da177e4SLinus Torvalds return -EINVAL; 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds 870d6182223SPaul Gortmaker max = count; 871d6182223SPaul Gortmaker tmp = count_trail_chars(user_buffer, max); 8721da177e4SLinus Torvalds if (tmp < 0) { 873f9467eaeSJoe Perches pr_warning("illegal format\n"); 8741da177e4SLinus Torvalds return tmp; 8751da177e4SLinus Torvalds } 876d6182223SPaul Gortmaker i = tmp; 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds /* Read variable name */ 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 88163adc6fbSStephen Hemminger if (len < 0) 882222f1806SLuiz Capitulino return len; 88363adc6fbSStephen Hemminger 8841da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 8851da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 8861da177e4SLinus Torvalds return -EFAULT; 8871da177e4SLinus Torvalds i += len; 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds max = count - i; 8901da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 8911da177e4SLinus Torvalds if (len < 0) 8921da177e4SLinus Torvalds return len; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds i += len; 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds if (debug) { 89786c2c0a8SDmitry Torokhov size_t copy = min_t(size_t, count, 1023); 898448d7b5dSNelson Elhage char tb[copy + 1]; 899448d7b5dSNelson Elhage if (copy_from_user(tb, user_buffer, copy)) 9001da177e4SLinus Torvalds return -EFAULT; 901448d7b5dSNelson Elhage tb[copy] = 0; 90225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: %s,%lu buffer -:%s:-\n", name, 903d50a6b56SStephen Hemminger (unsigned long)count, tb); 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds if (!strcmp(name, "min_pkt_size")) { 9071da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 90863adc6fbSStephen Hemminger if (len < 0) 909222f1806SLuiz Capitulino return len; 91063adc6fbSStephen Hemminger 9111da177e4SLinus Torvalds i += len; 9121da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9131da177e4SLinus Torvalds value = 14 + 20 + 8; 9141da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9151da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9161da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9171da177e4SLinus Torvalds } 918222f1806SLuiz Capitulino sprintf(pg_result, "OK: min_pkt_size=%u", 919222f1806SLuiz Capitulino pkt_dev->min_pkt_size); 9201da177e4SLinus Torvalds return count; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds if (!strcmp(name, "max_pkt_size")) { 9241da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 92563adc6fbSStephen Hemminger if (len < 0) 926222f1806SLuiz Capitulino return len; 92763adc6fbSStephen Hemminger 9281da177e4SLinus Torvalds i += len; 9291da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9301da177e4SLinus Torvalds value = 14 + 20 + 8; 9311da177e4SLinus Torvalds if (value != pkt_dev->max_pkt_size) { 9321da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9331da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9341da177e4SLinus Torvalds } 935222f1806SLuiz Capitulino sprintf(pg_result, "OK: max_pkt_size=%u", 936222f1806SLuiz Capitulino pkt_dev->max_pkt_size); 9371da177e4SLinus Torvalds return count; 9381da177e4SLinus Torvalds } 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds /* Shortcut for min = max */ 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds if (!strcmp(name, "pkt_size")) { 9431da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 94463adc6fbSStephen Hemminger if (len < 0) 945222f1806SLuiz Capitulino return len; 94663adc6fbSStephen Hemminger 9471da177e4SLinus Torvalds i += len; 9481da177e4SLinus Torvalds if (value < 14 + 20 + 8) 9491da177e4SLinus Torvalds value = 14 + 20 + 8; 9501da177e4SLinus Torvalds if (value != pkt_dev->min_pkt_size) { 9511da177e4SLinus Torvalds pkt_dev->min_pkt_size = value; 9521da177e4SLinus Torvalds pkt_dev->max_pkt_size = value; 9531da177e4SLinus Torvalds pkt_dev->cur_pkt_size = value; 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); 9561da177e4SLinus Torvalds return count; 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds if (!strcmp(name, "debug")) { 9601da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 96163adc6fbSStephen Hemminger if (len < 0) 962222f1806SLuiz Capitulino return len; 96363adc6fbSStephen Hemminger 9641da177e4SLinus Torvalds i += len; 9651da177e4SLinus Torvalds debug = value; 9661da177e4SLinus Torvalds sprintf(pg_result, "OK: debug=%u", debug); 9671da177e4SLinus Torvalds return count; 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds if (!strcmp(name, "frags")) { 9711da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 97263adc6fbSStephen Hemminger if (len < 0) 973222f1806SLuiz Capitulino return len; 97463adc6fbSStephen Hemminger 9751da177e4SLinus Torvalds i += len; 9761da177e4SLinus Torvalds pkt_dev->nfrags = value; 9771da177e4SLinus Torvalds sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); 9781da177e4SLinus Torvalds return count; 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds if (!strcmp(name, "delay")) { 9811da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 98263adc6fbSStephen Hemminger if (len < 0) 983222f1806SLuiz Capitulino return len; 98463adc6fbSStephen Hemminger 9851da177e4SLinus Torvalds i += len; 986fd29cf72SStephen Hemminger if (value == 0x7FFFFFFF) 987fd29cf72SStephen Hemminger pkt_dev->delay = ULLONG_MAX; 988fd29cf72SStephen Hemminger else 9899240d715SEric Dumazet pkt_dev->delay = (u64)value; 990fd29cf72SStephen Hemminger 991fd29cf72SStephen Hemminger sprintf(pg_result, "OK: delay=%llu", 992fd29cf72SStephen Hemminger (unsigned long long) pkt_dev->delay); 9931da177e4SLinus Torvalds return count; 9941da177e4SLinus Torvalds } 99543d28b65SDaniel Turull if (!strcmp(name, "rate")) { 99643d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 99743d28b65SDaniel Turull if (len < 0) 99843d28b65SDaniel Turull return len; 99943d28b65SDaniel Turull 100043d28b65SDaniel Turull i += len; 100143d28b65SDaniel Turull if (!value) 100243d28b65SDaniel Turull return len; 100343d28b65SDaniel Turull pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value; 100443d28b65SDaniel Turull if (debug) 1005f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 100643d28b65SDaniel Turull 100743d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 100843d28b65SDaniel Turull return count; 100943d28b65SDaniel Turull } 101043d28b65SDaniel Turull if (!strcmp(name, "ratep")) { 101143d28b65SDaniel Turull len = num_arg(&user_buffer[i], 10, &value); 101243d28b65SDaniel Turull if (len < 0) 101343d28b65SDaniel Turull return len; 101443d28b65SDaniel Turull 101543d28b65SDaniel Turull i += len; 101643d28b65SDaniel Turull if (!value) 101743d28b65SDaniel Turull return len; 101843d28b65SDaniel Turull pkt_dev->delay = NSEC_PER_SEC/value; 101943d28b65SDaniel Turull if (debug) 1020f9467eaeSJoe Perches pr_info("Delay set at: %llu ns\n", pkt_dev->delay); 102143d28b65SDaniel Turull 102243d28b65SDaniel Turull sprintf(pg_result, "OK: rate=%lu", value); 102343d28b65SDaniel Turull return count; 102443d28b65SDaniel Turull } 10251da177e4SLinus Torvalds if (!strcmp(name, "udp_src_min")) { 10261da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 102763adc6fbSStephen Hemminger if (len < 0) 1028222f1806SLuiz Capitulino return len; 102963adc6fbSStephen Hemminger 10301da177e4SLinus Torvalds i += len; 10311da177e4SLinus Torvalds if (value != pkt_dev->udp_src_min) { 10321da177e4SLinus Torvalds pkt_dev->udp_src_min = value; 10331da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10341da177e4SLinus Torvalds } 10351da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); 10361da177e4SLinus Torvalds return count; 10371da177e4SLinus Torvalds } 10381da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_min")) { 10391da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 104063adc6fbSStephen Hemminger if (len < 0) 1041222f1806SLuiz Capitulino return len; 104263adc6fbSStephen Hemminger 10431da177e4SLinus Torvalds i += len; 10441da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_min) { 10451da177e4SLinus Torvalds pkt_dev->udp_dst_min = value; 10461da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); 10491da177e4SLinus Torvalds return count; 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds if (!strcmp(name, "udp_src_max")) { 10521da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 105363adc6fbSStephen Hemminger if (len < 0) 1054222f1806SLuiz Capitulino return len; 105563adc6fbSStephen Hemminger 10561da177e4SLinus Torvalds i += len; 10571da177e4SLinus Torvalds if (value != pkt_dev->udp_src_max) { 10581da177e4SLinus Torvalds pkt_dev->udp_src_max = value; 10591da177e4SLinus Torvalds pkt_dev->cur_udp_src = value; 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); 10621da177e4SLinus Torvalds return count; 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds if (!strcmp(name, "udp_dst_max")) { 10651da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 106663adc6fbSStephen Hemminger if (len < 0) 1067222f1806SLuiz Capitulino return len; 106863adc6fbSStephen Hemminger 10691da177e4SLinus Torvalds i += len; 10701da177e4SLinus Torvalds if (value != pkt_dev->udp_dst_max) { 10711da177e4SLinus Torvalds pkt_dev->udp_dst_max = value; 10721da177e4SLinus Torvalds pkt_dev->cur_udp_dst = value; 10731da177e4SLinus Torvalds } 10741da177e4SLinus Torvalds sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); 10751da177e4SLinus Torvalds return count; 10761da177e4SLinus Torvalds } 10771da177e4SLinus Torvalds if (!strcmp(name, "clone_skb")) { 10781da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 107963adc6fbSStephen Hemminger if (len < 0) 1080222f1806SLuiz Capitulino return len; 108163adc6fbSStephen Hemminger 10821da177e4SLinus Torvalds i += len; 10831da177e4SLinus Torvalds pkt_dev->clone_skb = value; 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); 10861da177e4SLinus Torvalds return count; 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds if (!strcmp(name, "count")) { 10891da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 109063adc6fbSStephen Hemminger if (len < 0) 1091222f1806SLuiz Capitulino return len; 109263adc6fbSStephen Hemminger 10931da177e4SLinus Torvalds i += len; 10941da177e4SLinus Torvalds pkt_dev->count = value; 10951da177e4SLinus Torvalds sprintf(pg_result, "OK: count=%llu", 10961da177e4SLinus Torvalds (unsigned long long)pkt_dev->count); 10971da177e4SLinus Torvalds return count; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds if (!strcmp(name, "src_mac_count")) { 11001da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 110163adc6fbSStephen Hemminger if (len < 0) 1102222f1806SLuiz Capitulino return len; 110363adc6fbSStephen Hemminger 11041da177e4SLinus Torvalds i += len; 11051da177e4SLinus Torvalds if (pkt_dev->src_mac_count != value) { 11061da177e4SLinus Torvalds pkt_dev->src_mac_count = value; 11071da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 11081da177e4SLinus Torvalds } 1109222f1806SLuiz Capitulino sprintf(pg_result, "OK: src_mac_count=%d", 1110222f1806SLuiz Capitulino pkt_dev->src_mac_count); 11111da177e4SLinus Torvalds return count; 11121da177e4SLinus Torvalds } 11131da177e4SLinus Torvalds if (!strcmp(name, "dst_mac_count")) { 11141da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 111563adc6fbSStephen Hemminger if (len < 0) 1116222f1806SLuiz Capitulino return len; 111763adc6fbSStephen Hemminger 11181da177e4SLinus Torvalds i += len; 11191da177e4SLinus Torvalds if (pkt_dev->dst_mac_count != value) { 11201da177e4SLinus Torvalds pkt_dev->dst_mac_count = value; 11211da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 11221da177e4SLinus Torvalds } 1123222f1806SLuiz Capitulino sprintf(pg_result, "OK: dst_mac_count=%d", 1124222f1806SLuiz Capitulino pkt_dev->dst_mac_count); 11251da177e4SLinus Torvalds return count; 11261da177e4SLinus Torvalds } 1127e99b99b4SRobert Olsson if (!strcmp(name, "node")) { 1128e99b99b4SRobert Olsson len = num_arg(&user_buffer[i], 10, &value); 1129e99b99b4SRobert Olsson if (len < 0) 1130e99b99b4SRobert Olsson return len; 1131e99b99b4SRobert Olsson 1132e99b99b4SRobert Olsson i += len; 1133e99b99b4SRobert Olsson 1134e99b99b4SRobert Olsson if (node_possible(value)) { 1135e99b99b4SRobert Olsson pkt_dev->node = value; 1136e99b99b4SRobert Olsson sprintf(pg_result, "OK: node=%d", pkt_dev->node); 1137e99b99b4SRobert Olsson } 1138e99b99b4SRobert Olsson else 1139e99b99b4SRobert Olsson sprintf(pg_result, "ERROR: node not possible"); 1140e99b99b4SRobert Olsson return count; 1141e99b99b4SRobert Olsson } 11421da177e4SLinus Torvalds if (!strcmp(name, "flag")) { 11431da177e4SLinus Torvalds char f[32]; 11441da177e4SLinus Torvalds memset(f, 0, 32); 11451da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 114663adc6fbSStephen Hemminger if (len < 0) 1147222f1806SLuiz Capitulino return len; 114863adc6fbSStephen Hemminger 11491da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 11501da177e4SLinus Torvalds return -EFAULT; 11511da177e4SLinus Torvalds i += len; 11521da177e4SLinus Torvalds if (strcmp(f, "IPSRC_RND") == 0) 11531da177e4SLinus Torvalds pkt_dev->flags |= F_IPSRC_RND; 11541da177e4SLinus Torvalds 11551da177e4SLinus Torvalds else if (strcmp(f, "!IPSRC_RND") == 0) 11561da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPSRC_RND; 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds else if (strcmp(f, "TXSIZE_RND") == 0) 11591da177e4SLinus Torvalds pkt_dev->flags |= F_TXSIZE_RND; 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds else if (strcmp(f, "!TXSIZE_RND") == 0) 11621da177e4SLinus Torvalds pkt_dev->flags &= ~F_TXSIZE_RND; 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds else if (strcmp(f, "IPDST_RND") == 0) 11651da177e4SLinus Torvalds pkt_dev->flags |= F_IPDST_RND; 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds else if (strcmp(f, "!IPDST_RND") == 0) 11681da177e4SLinus Torvalds pkt_dev->flags &= ~F_IPDST_RND; 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds else if (strcmp(f, "UDPSRC_RND") == 0) 11711da177e4SLinus Torvalds pkt_dev->flags |= F_UDPSRC_RND; 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds else if (strcmp(f, "!UDPSRC_RND") == 0) 11741da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPSRC_RND; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds else if (strcmp(f, "UDPDST_RND") == 0) 11771da177e4SLinus Torvalds pkt_dev->flags |= F_UDPDST_RND; 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds else if (strcmp(f, "!UDPDST_RND") == 0) 11801da177e4SLinus Torvalds pkt_dev->flags &= ~F_UDPDST_RND; 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds else if (strcmp(f, "MACSRC_RND") == 0) 11831da177e4SLinus Torvalds pkt_dev->flags |= F_MACSRC_RND; 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds else if (strcmp(f, "!MACSRC_RND") == 0) 11861da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACSRC_RND; 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds else if (strcmp(f, "MACDST_RND") == 0) 11891da177e4SLinus Torvalds pkt_dev->flags |= F_MACDST_RND; 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds else if (strcmp(f, "!MACDST_RND") == 0) 11921da177e4SLinus Torvalds pkt_dev->flags &= ~F_MACDST_RND; 11931da177e4SLinus Torvalds 1194ca6549afSSteven Whitehouse else if (strcmp(f, "MPLS_RND") == 0) 1195ca6549afSSteven Whitehouse pkt_dev->flags |= F_MPLS_RND; 1196ca6549afSSteven Whitehouse 1197ca6549afSSteven Whitehouse else if (strcmp(f, "!MPLS_RND") == 0) 1198ca6549afSSteven Whitehouse pkt_dev->flags &= ~F_MPLS_RND; 1199ca6549afSSteven Whitehouse 120034954ddcSFrancesco Fondelli else if (strcmp(f, "VID_RND") == 0) 120134954ddcSFrancesco Fondelli pkt_dev->flags |= F_VID_RND; 120234954ddcSFrancesco Fondelli 120334954ddcSFrancesco Fondelli else if (strcmp(f, "!VID_RND") == 0) 120434954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_VID_RND; 120534954ddcSFrancesco Fondelli 120634954ddcSFrancesco Fondelli else if (strcmp(f, "SVID_RND") == 0) 120734954ddcSFrancesco Fondelli pkt_dev->flags |= F_SVID_RND; 120834954ddcSFrancesco Fondelli 120934954ddcSFrancesco Fondelli else if (strcmp(f, "!SVID_RND") == 0) 121034954ddcSFrancesco Fondelli pkt_dev->flags &= ~F_SVID_RND; 121134954ddcSFrancesco Fondelli 1212007a531bSJamal Hadi Salim else if (strcmp(f, "FLOW_SEQ") == 0) 1213007a531bSJamal Hadi Salim pkt_dev->flags |= F_FLOW_SEQ; 1214007a531bSJamal Hadi Salim 121545b270f8SRobert Olsson else if (strcmp(f, "QUEUE_MAP_RND") == 0) 121645b270f8SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_RND; 121745b270f8SRobert Olsson 121845b270f8SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_RND") == 0) 121945b270f8SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_RND; 1220e6fce5b9SRobert Olsson 1221e6fce5b9SRobert Olsson else if (strcmp(f, "QUEUE_MAP_CPU") == 0) 1222e6fce5b9SRobert Olsson pkt_dev->flags |= F_QUEUE_MAP_CPU; 1223e6fce5b9SRobert Olsson 1224e6fce5b9SRobert Olsson else if (strcmp(f, "!QUEUE_MAP_CPU") == 0) 1225e6fce5b9SRobert Olsson pkt_dev->flags &= ~F_QUEUE_MAP_CPU; 1226a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 1227a553e4a6SJamal Hadi Salim else if (strcmp(f, "IPSEC") == 0) 1228a553e4a6SJamal Hadi Salim pkt_dev->flags |= F_IPSEC_ON; 1229a553e4a6SJamal Hadi Salim #endif 1230a553e4a6SJamal Hadi Salim 12311ca7768cSFrancesco Fondelli else if (strcmp(f, "!IPV6") == 0) 12321ca7768cSFrancesco Fondelli pkt_dev->flags &= ~F_IPV6; 12331ca7768cSFrancesco Fondelli 1234e99b99b4SRobert Olsson else if (strcmp(f, "NODE_ALLOC") == 0) 1235e99b99b4SRobert Olsson pkt_dev->flags |= F_NODE; 1236e99b99b4SRobert Olsson 1237e99b99b4SRobert Olsson else if (strcmp(f, "!NODE_ALLOC") == 0) 1238e99b99b4SRobert Olsson pkt_dev->flags &= ~F_NODE; 1239e99b99b4SRobert Olsson 12401da177e4SLinus Torvalds else { 1241222f1806SLuiz Capitulino sprintf(pg_result, 1242222f1806SLuiz Capitulino "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", 12431da177e4SLinus Torvalds f, 12441ca7768cSFrancesco Fondelli "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " 1245e99b99b4SRobert Olsson "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n"); 12461da177e4SLinus Torvalds return count; 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); 12491da177e4SLinus Torvalds return count; 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 12521da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); 125363adc6fbSStephen Hemminger if (len < 0) 1254222f1806SLuiz Capitulino return len; 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12571da177e4SLinus Torvalds return -EFAULT; 12581da177e4SLinus Torvalds buf[len] = 0; 12591da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_min) != 0) { 12601da177e4SLinus Torvalds memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); 12611da177e4SLinus Torvalds strncpy(pkt_dev->dst_min, buf, len); 12621da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 12631da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds if (debug) 126625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_min set to: %s\n", 1267222f1806SLuiz Capitulino pkt_dev->dst_min); 12681da177e4SLinus Torvalds i += len; 12691da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); 12701da177e4SLinus Torvalds return count; 12711da177e4SLinus Torvalds } 12721da177e4SLinus Torvalds if (!strcmp(name, "dst_max")) { 12731da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); 127463adc6fbSStephen Hemminger if (len < 0) 1275222f1806SLuiz Capitulino return len; 127663adc6fbSStephen Hemminger 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 12791da177e4SLinus Torvalds return -EFAULT; 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds buf[len] = 0; 12821da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->dst_max) != 0) { 12831da177e4SLinus Torvalds memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); 12841da177e4SLinus Torvalds strncpy(pkt_dev->dst_max, buf, len); 12851da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 12861da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_max; 12871da177e4SLinus Torvalds } 12881da177e4SLinus Torvalds if (debug) 128925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst_max set to: %s\n", 1290222f1806SLuiz Capitulino pkt_dev->dst_max); 12911da177e4SLinus Torvalds i += len; 12921da177e4SLinus Torvalds sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); 12931da177e4SLinus Torvalds return count; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds if (!strcmp(name, "dst6")) { 12961da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1297222f1806SLuiz Capitulino if (len < 0) 1298222f1806SLuiz Capitulino return len; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13011da177e4SLinus Torvalds 13021da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13031da177e4SLinus Torvalds return -EFAULT; 13041da177e4SLinus Torvalds buf[len] = 0; 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13071da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); 13101da177e4SLinus Torvalds 13111da177e4SLinus Torvalds if (debug) 131225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf); 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds i += len; 13151da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6=%s", buf); 13161da177e4SLinus Torvalds return count; 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds if (!strcmp(name, "dst6_min")) { 13191da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1320222f1806SLuiz Capitulino if (len < 0) 1321222f1806SLuiz Capitulino return len; 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13241da177e4SLinus Torvalds 13251da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13261da177e4SLinus Torvalds return -EFAULT; 13271da177e4SLinus Torvalds buf[len] = 0; 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13301da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); 13311da177e4SLinus Torvalds 1332222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev->cur_in6_daddr, 1333222f1806SLuiz Capitulino &pkt_dev->min_in6_daddr); 13341da177e4SLinus Torvalds if (debug) 133525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf); 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds i += len; 13381da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_min=%s", buf); 13391da177e4SLinus Torvalds return count; 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds if (!strcmp(name, "dst6_max")) { 13421da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1343222f1806SLuiz Capitulino if (len < 0) 1344222f1806SLuiz Capitulino return len; 13451da177e4SLinus Torvalds 13461da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13491da177e4SLinus Torvalds return -EFAULT; 13501da177e4SLinus Torvalds buf[len] = 0; 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13531da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds if (debug) 135625a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds i += len; 13591da177e4SLinus Torvalds sprintf(pg_result, "OK: dst6_max=%s", buf); 13601da177e4SLinus Torvalds return count; 13611da177e4SLinus Torvalds } 13621da177e4SLinus Torvalds if (!strcmp(name, "src6")) { 13631da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(buf) - 1); 1364222f1806SLuiz Capitulino if (len < 0) 1365222f1806SLuiz Capitulino return len; 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds pkt_dev->flags |= F_IPV6; 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13701da177e4SLinus Torvalds return -EFAULT; 13711da177e4SLinus Torvalds buf[len] = 0; 13721da177e4SLinus Torvalds 13731da177e4SLinus Torvalds scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13741da177e4SLinus Torvalds fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); 13751da177e4SLinus Torvalds 13761da177e4SLinus Torvalds ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds if (debug) 137925a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf); 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds i += len; 13821da177e4SLinus Torvalds sprintf(pg_result, "OK: src6=%s", buf); 13831da177e4SLinus Torvalds return count; 13841da177e4SLinus Torvalds } 13851da177e4SLinus Torvalds if (!strcmp(name, "src_min")) { 13861da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); 138763adc6fbSStephen Hemminger if (len < 0) 1388222f1806SLuiz Capitulino return len; 138963adc6fbSStephen Hemminger 13901da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 13911da177e4SLinus Torvalds return -EFAULT; 13921da177e4SLinus Torvalds buf[len] = 0; 13931da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_min) != 0) { 13941da177e4SLinus Torvalds memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); 13951da177e4SLinus Torvalds strncpy(pkt_dev->src_min, buf, len); 13961da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 13971da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds if (debug) 140025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_min set to: %s\n", 1401222f1806SLuiz Capitulino pkt_dev->src_min); 14021da177e4SLinus Torvalds i += len; 14031da177e4SLinus Torvalds sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); 14041da177e4SLinus Torvalds return count; 14051da177e4SLinus Torvalds } 14061da177e4SLinus Torvalds if (!strcmp(name, "src_max")) { 14071da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); 140863adc6fbSStephen Hemminger if (len < 0) 1409222f1806SLuiz Capitulino return len; 141063adc6fbSStephen Hemminger 14111da177e4SLinus Torvalds if (copy_from_user(buf, &user_buffer[i], len)) 14121da177e4SLinus Torvalds return -EFAULT; 14131da177e4SLinus Torvalds buf[len] = 0; 14141da177e4SLinus Torvalds if (strcmp(buf, pkt_dev->src_max) != 0) { 14151da177e4SLinus Torvalds memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); 14161da177e4SLinus Torvalds strncpy(pkt_dev->src_max, buf, len); 14171da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 14181da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_max; 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds if (debug) 142125a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: src_max set to: %s\n", 1422222f1806SLuiz Capitulino pkt_dev->src_max); 14231da177e4SLinus Torvalds i += len; 14241da177e4SLinus Torvalds sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); 14251da177e4SLinus Torvalds return count; 14261da177e4SLinus Torvalds } 14271da177e4SLinus Torvalds if (!strcmp(name, "dst_mac")) { 14281da177e4SLinus Torvalds char *v = valstr; 1429f404e9a6SKris Katterjohn unsigned char old_dmac[ETH_ALEN]; 14301da177e4SLinus Torvalds unsigned char *m = pkt_dev->dst_mac; 1431f404e9a6SKris Katterjohn memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 143463adc6fbSStephen Hemminger if (len < 0) 1435222f1806SLuiz Capitulino return len; 143663adc6fbSStephen Hemminger 14371da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14381da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14391da177e4SLinus Torvalds return -EFAULT; 14401da177e4SLinus Torvalds i += len; 14411da177e4SLinus Torvalds 14421da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { 1443451e07a2SAndy Shevchenko int value; 1444451e07a2SAndy Shevchenko 1445451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1446451e07a2SAndy Shevchenko if (value >= 0) 1447451e07a2SAndy Shevchenko *m = *m * 16 + value; 1448451e07a2SAndy Shevchenko 14491da177e4SLinus Torvalds if (*v == ':') { 14501da177e4SLinus Torvalds m++; 14511da177e4SLinus Torvalds *m = 0; 14521da177e4SLinus Torvalds } 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds 14551da177e4SLinus Torvalds /* Set up Dest MAC */ 1456f404e9a6SKris Katterjohn if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) 1457f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds sprintf(pg_result, "OK: dstmac"); 14601da177e4SLinus Torvalds return count; 14611da177e4SLinus Torvalds } 14621da177e4SLinus Torvalds if (!strcmp(name, "src_mac")) { 14631da177e4SLinus Torvalds char *v = valstr; 1464ce5d0b47SAdit Ranadive unsigned char old_smac[ETH_ALEN]; 14651da177e4SLinus Torvalds unsigned char *m = pkt_dev->src_mac; 14661da177e4SLinus Torvalds 1467ce5d0b47SAdit Ranadive memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); 1468ce5d0b47SAdit Ranadive 14691da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(valstr) - 1); 147063adc6fbSStephen Hemminger if (len < 0) 1471222f1806SLuiz Capitulino return len; 147263adc6fbSStephen Hemminger 14731da177e4SLinus Torvalds memset(valstr, 0, sizeof(valstr)); 14741da177e4SLinus Torvalds if (copy_from_user(valstr, &user_buffer[i], len)) 14751da177e4SLinus Torvalds return -EFAULT; 14761da177e4SLinus Torvalds i += len; 14771da177e4SLinus Torvalds 14781da177e4SLinus Torvalds for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { 1479451e07a2SAndy Shevchenko int value; 1480451e07a2SAndy Shevchenko 1481451e07a2SAndy Shevchenko value = hex_to_bin(*v); 1482451e07a2SAndy Shevchenko if (value >= 0) 1483451e07a2SAndy Shevchenko *m = *m * 16 + value; 1484451e07a2SAndy Shevchenko 14851da177e4SLinus Torvalds if (*v == ':') { 14861da177e4SLinus Torvalds m++; 14871da177e4SLinus Torvalds *m = 0; 14881da177e4SLinus Torvalds } 14891da177e4SLinus Torvalds } 14901da177e4SLinus Torvalds 1491ce5d0b47SAdit Ranadive /* Set up Src MAC */ 1492ce5d0b47SAdit Ranadive if (compare_ether_addr(old_smac, pkt_dev->src_mac)) 1493ce5d0b47SAdit Ranadive memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); 1494ce5d0b47SAdit Ranadive 14951da177e4SLinus Torvalds sprintf(pg_result, "OK: srcmac"); 14961da177e4SLinus Torvalds return count; 14971da177e4SLinus Torvalds } 14981da177e4SLinus Torvalds 14991da177e4SLinus Torvalds if (!strcmp(name, "clear_counters")) { 15001da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 15011da177e4SLinus Torvalds sprintf(pg_result, "OK: Clearing counters.\n"); 15021da177e4SLinus Torvalds return count; 15031da177e4SLinus Torvalds } 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds if (!strcmp(name, "flows")) { 15061da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 150763adc6fbSStephen Hemminger if (len < 0) 1508222f1806SLuiz Capitulino return len; 150963adc6fbSStephen Hemminger 15101da177e4SLinus Torvalds i += len; 15111da177e4SLinus Torvalds if (value > MAX_CFLOWS) 15121da177e4SLinus Torvalds value = MAX_CFLOWS; 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds pkt_dev->cflows = value; 15151da177e4SLinus Torvalds sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows); 15161da177e4SLinus Torvalds return count; 15171da177e4SLinus Torvalds } 15181da177e4SLinus Torvalds 15191da177e4SLinus Torvalds if (!strcmp(name, "flowlen")) { 15201da177e4SLinus Torvalds len = num_arg(&user_buffer[i], 10, &value); 152163adc6fbSStephen Hemminger if (len < 0) 1522222f1806SLuiz Capitulino return len; 152363adc6fbSStephen Hemminger 15241da177e4SLinus Torvalds i += len; 15251da177e4SLinus Torvalds pkt_dev->lflow = value; 15261da177e4SLinus Torvalds sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); 15271da177e4SLinus Torvalds return count; 15281da177e4SLinus Torvalds } 15291da177e4SLinus Torvalds 153045b270f8SRobert Olsson if (!strcmp(name, "queue_map_min")) { 153145b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 153263adc6fbSStephen Hemminger if (len < 0) 153345b270f8SRobert Olsson return len; 153463adc6fbSStephen Hemminger 153545b270f8SRobert Olsson i += len; 153645b270f8SRobert Olsson pkt_dev->queue_map_min = value; 153745b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min); 153845b270f8SRobert Olsson return count; 153945b270f8SRobert Olsson } 154045b270f8SRobert Olsson 154145b270f8SRobert Olsson if (!strcmp(name, "queue_map_max")) { 154245b270f8SRobert Olsson len = num_arg(&user_buffer[i], 5, &value); 154363adc6fbSStephen Hemminger if (len < 0) 154445b270f8SRobert Olsson return len; 154563adc6fbSStephen Hemminger 154645b270f8SRobert Olsson i += len; 154745b270f8SRobert Olsson pkt_dev->queue_map_max = value; 154845b270f8SRobert Olsson sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); 154945b270f8SRobert Olsson return count; 155045b270f8SRobert Olsson } 155145b270f8SRobert Olsson 1552ca6549afSSteven Whitehouse if (!strcmp(name, "mpls")) { 1553cfcabdccSStephen Hemminger unsigned n, cnt; 1554cfcabdccSStephen Hemminger 1555ca6549afSSteven Whitehouse len = get_labels(&user_buffer[i], pkt_dev); 1556cfcabdccSStephen Hemminger if (len < 0) 1557cfcabdccSStephen Hemminger return len; 1558ca6549afSSteven Whitehouse i += len; 1559cfcabdccSStephen Hemminger cnt = sprintf(pg_result, "OK: mpls="); 1560ca6549afSSteven Whitehouse for (n = 0; n < pkt_dev->nr_labels; n++) 1561cfcabdccSStephen Hemminger cnt += sprintf(pg_result + cnt, 1562ca6549afSSteven Whitehouse "%08x%s", ntohl(pkt_dev->labels[n]), 1563ca6549afSSteven Whitehouse n == pkt_dev->nr_labels-1 ? "" : ","); 156434954ddcSFrancesco Fondelli 156534954ddcSFrancesco Fondelli if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { 156634954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 156734954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 156834954ddcSFrancesco Fondelli 156934954ddcSFrancesco Fondelli if (debug) 157025a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); 157134954ddcSFrancesco Fondelli } 157234954ddcSFrancesco Fondelli return count; 157334954ddcSFrancesco Fondelli } 157434954ddcSFrancesco Fondelli 157534954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_id")) { 157634954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 157763adc6fbSStephen Hemminger if (len < 0) 157834954ddcSFrancesco Fondelli return len; 157963adc6fbSStephen Hemminger 158034954ddcSFrancesco Fondelli i += len; 158134954ddcSFrancesco Fondelli if (value <= 4095) { 158234954ddcSFrancesco Fondelli pkt_dev->vlan_id = value; /* turn on VLAN */ 158334954ddcSFrancesco Fondelli 158434954ddcSFrancesco Fondelli if (debug) 158525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN turned on\n"); 158634954ddcSFrancesco Fondelli 158734954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 158825a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 158934954ddcSFrancesco Fondelli 159034954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 159134954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); 159234954ddcSFrancesco Fondelli } else { 159334954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 159434954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 159534954ddcSFrancesco Fondelli 159634954ddcSFrancesco Fondelli if (debug) 159725a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 159834954ddcSFrancesco Fondelli } 159934954ddcSFrancesco Fondelli return count; 160034954ddcSFrancesco Fondelli } 160134954ddcSFrancesco Fondelli 160234954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_p")) { 160334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 160463adc6fbSStephen Hemminger if (len < 0) 160534954ddcSFrancesco Fondelli return len; 160663adc6fbSStephen Hemminger 160734954ddcSFrancesco Fondelli i += len; 160834954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { 160934954ddcSFrancesco Fondelli pkt_dev->vlan_p = value; 161034954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); 161134954ddcSFrancesco Fondelli } else { 161234954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_p must be 0-7"); 161334954ddcSFrancesco Fondelli } 161434954ddcSFrancesco Fondelli return count; 161534954ddcSFrancesco Fondelli } 161634954ddcSFrancesco Fondelli 161734954ddcSFrancesco Fondelli if (!strcmp(name, "vlan_cfi")) { 161834954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 161963adc6fbSStephen Hemminger if (len < 0) 162034954ddcSFrancesco Fondelli return len; 162163adc6fbSStephen Hemminger 162234954ddcSFrancesco Fondelli i += len; 162334954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { 162434954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = value; 162534954ddcSFrancesco Fondelli sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); 162634954ddcSFrancesco Fondelli } else { 162734954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); 162834954ddcSFrancesco Fondelli } 162934954ddcSFrancesco Fondelli return count; 163034954ddcSFrancesco Fondelli } 163134954ddcSFrancesco Fondelli 163234954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_id")) { 163334954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 4, &value); 163463adc6fbSStephen Hemminger if (len < 0) 163534954ddcSFrancesco Fondelli return len; 163663adc6fbSStephen Hemminger 163734954ddcSFrancesco Fondelli i += len; 163834954ddcSFrancesco Fondelli if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { 163934954ddcSFrancesco Fondelli pkt_dev->svlan_id = value; /* turn on SVLAN */ 164034954ddcSFrancesco Fondelli 164134954ddcSFrancesco Fondelli if (debug) 164225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); 164334954ddcSFrancesco Fondelli 164434954ddcSFrancesco Fondelli if (debug && pkt_dev->nr_labels) 164525a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); 164634954ddcSFrancesco Fondelli 164734954ddcSFrancesco Fondelli pkt_dev->nr_labels = 0; /* turn off MPLS */ 164834954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); 164934954ddcSFrancesco Fondelli } else { 165034954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ 165134954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 165234954ddcSFrancesco Fondelli 165334954ddcSFrancesco Fondelli if (debug) 165425a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); 165534954ddcSFrancesco Fondelli } 165634954ddcSFrancesco Fondelli return count; 165734954ddcSFrancesco Fondelli } 165834954ddcSFrancesco Fondelli 165934954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_p")) { 166034954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 166163adc6fbSStephen Hemminger if (len < 0) 166234954ddcSFrancesco Fondelli return len; 166363adc6fbSStephen Hemminger 166434954ddcSFrancesco Fondelli i += len; 166534954ddcSFrancesco Fondelli if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { 166634954ddcSFrancesco Fondelli pkt_dev->svlan_p = value; 166734954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); 166834954ddcSFrancesco Fondelli } else { 166934954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_p must be 0-7"); 167034954ddcSFrancesco Fondelli } 167134954ddcSFrancesco Fondelli return count; 167234954ddcSFrancesco Fondelli } 167334954ddcSFrancesco Fondelli 167434954ddcSFrancesco Fondelli if (!strcmp(name, "svlan_cfi")) { 167534954ddcSFrancesco Fondelli len = num_arg(&user_buffer[i], 1, &value); 167663adc6fbSStephen Hemminger if (len < 0) 167734954ddcSFrancesco Fondelli return len; 167863adc6fbSStephen Hemminger 167934954ddcSFrancesco Fondelli i += len; 168034954ddcSFrancesco Fondelli if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { 168134954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = value; 168234954ddcSFrancesco Fondelli sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); 168334954ddcSFrancesco Fondelli } else { 168434954ddcSFrancesco Fondelli sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); 168534954ddcSFrancesco Fondelli } 1686ca6549afSSteven Whitehouse return count; 1687ca6549afSSteven Whitehouse } 1688ca6549afSSteven Whitehouse 16891ca7768cSFrancesco Fondelli if (!strcmp(name, "tos")) { 16901ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 16911ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 169263adc6fbSStephen Hemminger if (len < 0) 16931ca7768cSFrancesco Fondelli return len; 169463adc6fbSStephen Hemminger 16951ca7768cSFrancesco Fondelli i += len; 16961ca7768cSFrancesco Fondelli if (len == 2) { 16971ca7768cSFrancesco Fondelli pkt_dev->tos = tmp_value; 16981ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); 16991ca7768cSFrancesco Fondelli } else { 17001ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: tos must be 00-ff"); 17011ca7768cSFrancesco Fondelli } 17021ca7768cSFrancesco Fondelli return count; 17031ca7768cSFrancesco Fondelli } 17041ca7768cSFrancesco Fondelli 17051ca7768cSFrancesco Fondelli if (!strcmp(name, "traffic_class")) { 17061ca7768cSFrancesco Fondelli __u32 tmp_value = 0; 17071ca7768cSFrancesco Fondelli len = hex32_arg(&user_buffer[i], 2, &tmp_value); 170863adc6fbSStephen Hemminger if (len < 0) 17091ca7768cSFrancesco Fondelli return len; 171063adc6fbSStephen Hemminger 17111ca7768cSFrancesco Fondelli i += len; 17121ca7768cSFrancesco Fondelli if (len == 2) { 17131ca7768cSFrancesco Fondelli pkt_dev->traffic_class = tmp_value; 17141ca7768cSFrancesco Fondelli sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); 17151ca7768cSFrancesco Fondelli } else { 17161ca7768cSFrancesco Fondelli sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); 17171ca7768cSFrancesco Fondelli } 17181ca7768cSFrancesco Fondelli return count; 17191ca7768cSFrancesco Fondelli } 17201ca7768cSFrancesco Fondelli 17219e50e3acSJohn Fastabend if (!strcmp(name, "skb_priority")) { 17229e50e3acSJohn Fastabend len = num_arg(&user_buffer[i], 9, &value); 17239e50e3acSJohn Fastabend if (len < 0) 17249e50e3acSJohn Fastabend return len; 17259e50e3acSJohn Fastabend 17269e50e3acSJohn Fastabend i += len; 17279e50e3acSJohn Fastabend pkt_dev->skb_priority = value; 17289e50e3acSJohn Fastabend sprintf(pg_result, "OK: skb_priority=%i", 17299e50e3acSJohn Fastabend pkt_dev->skb_priority); 17309e50e3acSJohn Fastabend return count; 17319e50e3acSJohn Fastabend } 17329e50e3acSJohn Fastabend 17331da177e4SLinus Torvalds sprintf(pkt_dev->result, "No such parameter \"%s\"", name); 17341da177e4SLinus Torvalds return -EINVAL; 17351da177e4SLinus Torvalds } 17361da177e4SLinus Torvalds 1737d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file) 17381da177e4SLinus Torvalds { 1739d50a6b56SStephen Hemminger return single_open(file, pktgen_if_show, PDE(inode)->data); 17401da177e4SLinus Torvalds } 17411da177e4SLinus Torvalds 17429a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = { 1743d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1744d50a6b56SStephen Hemminger .open = pktgen_if_open, 1745d50a6b56SStephen Hemminger .read = seq_read, 1746d50a6b56SStephen Hemminger .llseek = seq_lseek, 1747d50a6b56SStephen Hemminger .write = pktgen_if_write, 1748d50a6b56SStephen Hemminger .release = single_release, 1749d50a6b56SStephen Hemminger }; 1750d50a6b56SStephen Hemminger 1751d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v) 1752d50a6b56SStephen Hemminger { 1753d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1754648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 1755d50a6b56SStephen Hemminger 1756d50a6b56SStephen Hemminger BUG_ON(!t); 1757d50a6b56SStephen Hemminger 1758d50a6b56SStephen Hemminger seq_printf(seq, "Running: "); 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds if_lock(t); 1761c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17621da177e4SLinus Torvalds if (pkt_dev->running) 1763593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17641da177e4SLinus Torvalds 1765d50a6b56SStephen Hemminger seq_printf(seq, "\nStopped: "); 17661da177e4SLinus Torvalds 1767c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 17681da177e4SLinus Torvalds if (!pkt_dev->running) 1769593f63b0SEric Dumazet seq_printf(seq, "%s ", pkt_dev->odevname); 17701da177e4SLinus Torvalds 17711da177e4SLinus Torvalds if (t->result[0]) 1772d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: %s\n", t->result); 17731da177e4SLinus Torvalds else 1774d50a6b56SStephen Hemminger seq_printf(seq, "\nResult: NA\n"); 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds if_unlock(t); 17771da177e4SLinus Torvalds 1778d50a6b56SStephen Hemminger return 0; 17791da177e4SLinus Torvalds } 17801da177e4SLinus Torvalds 1781d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file, 1782d50a6b56SStephen Hemminger const char __user * user_buffer, 1783d50a6b56SStephen Hemminger size_t count, loff_t * offset) 17841da177e4SLinus Torvalds { 17858a994a71SJoe Perches struct seq_file *seq = file->private_data; 1786d50a6b56SStephen Hemminger struct pktgen_thread *t = seq->private; 1787d6182223SPaul Gortmaker int i, max, len, ret; 17881da177e4SLinus Torvalds char name[40]; 17891da177e4SLinus Torvalds char *pg_result; 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds if (count < 1) { 17921da177e4SLinus Torvalds // sprintf(pg_result, "Wrong command format"); 17931da177e4SLinus Torvalds return -EINVAL; 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 1796d6182223SPaul Gortmaker max = count; 1797d6182223SPaul Gortmaker len = count_trail_chars(user_buffer, max); 17981da177e4SLinus Torvalds if (len < 0) 17991da177e4SLinus Torvalds return len; 18001da177e4SLinus Torvalds 1801d6182223SPaul Gortmaker i = len; 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds /* Read variable name */ 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(name) - 1); 18061da177e4SLinus Torvalds if (len < 0) 18071da177e4SLinus Torvalds return len; 18081da177e4SLinus Torvalds 18091da177e4SLinus Torvalds memset(name, 0, sizeof(name)); 18101da177e4SLinus Torvalds if (copy_from_user(name, &user_buffer[i], len)) 18111da177e4SLinus Torvalds return -EFAULT; 18121da177e4SLinus Torvalds i += len; 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds max = count - i; 18151da177e4SLinus Torvalds len = count_trail_chars(&user_buffer[i], max); 18161da177e4SLinus Torvalds if (len < 0) 18171da177e4SLinus Torvalds return len; 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds i += len; 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds if (debug) 182225a8b254SDavid S. Miller printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", 182325a8b254SDavid S. Miller name, (unsigned long)count); 18241da177e4SLinus Torvalds 18251da177e4SLinus Torvalds if (!t) { 1826f9467eaeSJoe Perches pr_err("ERROR: No thread\n"); 18271da177e4SLinus Torvalds ret = -EINVAL; 18281da177e4SLinus Torvalds goto out; 18291da177e4SLinus Torvalds } 18301da177e4SLinus Torvalds 18311da177e4SLinus Torvalds pg_result = &(t->result[0]); 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds if (!strcmp(name, "add_device")) { 18341da177e4SLinus Torvalds char f[32]; 18351da177e4SLinus Torvalds memset(f, 0, 32); 18361da177e4SLinus Torvalds len = strn_len(&user_buffer[i], sizeof(f) - 1); 18371da177e4SLinus Torvalds if (len < 0) { 18381da177e4SLinus Torvalds ret = len; 18391da177e4SLinus Torvalds goto out; 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds if (copy_from_user(f, &user_buffer[i], len)) 18421da177e4SLinus Torvalds return -EFAULT; 18431da177e4SLinus Torvalds i += len; 18446146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 18451da177e4SLinus Torvalds pktgen_add_device(t, f); 18466146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 18471da177e4SLinus Torvalds ret = count; 18481da177e4SLinus Torvalds sprintf(pg_result, "OK: add_device=%s", f); 18491da177e4SLinus Torvalds goto out; 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds 18521da177e4SLinus Torvalds if (!strcmp(name, "rem_device_all")) { 18536146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 185495ed63f7SArthur Kepner t->control |= T_REMDEVALL; 18556146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1856121caf57SNishanth Aravamudan schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ 18571da177e4SLinus Torvalds ret = count; 18581da177e4SLinus Torvalds sprintf(pg_result, "OK: rem_device_all"); 18591da177e4SLinus Torvalds goto out; 18601da177e4SLinus Torvalds } 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds if (!strcmp(name, "max_before_softirq")) { 1863b163911fSRobert Olsson sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); 18641da177e4SLinus Torvalds ret = count; 18651da177e4SLinus Torvalds goto out; 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds ret = -EINVAL; 18691da177e4SLinus Torvalds out: 18701da177e4SLinus Torvalds return ret; 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds 1873d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file) 18741da177e4SLinus Torvalds { 1875d50a6b56SStephen Hemminger return single_open(file, pktgen_thread_show, PDE(inode)->data); 18761da177e4SLinus Torvalds } 18771da177e4SLinus Torvalds 18789a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = { 1879d50a6b56SStephen Hemminger .owner = THIS_MODULE, 1880d50a6b56SStephen Hemminger .open = pktgen_thread_open, 1881d50a6b56SStephen Hemminger .read = seq_read, 1882d50a6b56SStephen Hemminger .llseek = seq_lseek, 1883d50a6b56SStephen Hemminger .write = pktgen_thread_write, 1884d50a6b56SStephen Hemminger .release = single_release, 1885d50a6b56SStephen Hemminger }; 18861da177e4SLinus Torvalds 18871da177e4SLinus Torvalds /* Think find or remove for NN */ 18881da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) 18891da177e4SLinus Torvalds { 18901da177e4SLinus Torvalds struct pktgen_thread *t; 18911da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 18923e984840SEric Dumazet bool exact = (remove == FIND); 18931da177e4SLinus Torvalds 1894cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 18953e984840SEric Dumazet pkt_dev = pktgen_find_dev(t, ifname, exact); 18961da177e4SLinus Torvalds if (pkt_dev) { 18971da177e4SLinus Torvalds if (remove) { 18981da177e4SLinus Torvalds if_lock(t); 189995ed63f7SArthur Kepner pkt_dev->removal_mark = 1; 190095ed63f7SArthur Kepner t->control |= T_REMDEV; 19011da177e4SLinus Torvalds if_unlock(t); 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds break; 19041da177e4SLinus Torvalds } 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds return pkt_dev; 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds 190995ed63f7SArthur Kepner /* 191095ed63f7SArthur Kepner * mark a device for removal 191195ed63f7SArthur Kepner */ 191239df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname) 19131da177e4SLinus Torvalds { 19141da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 191595ed63f7SArthur Kepner const int max_tries = 10, msec_per_try = 125; 191695ed63f7SArthur Kepner int i = 0; 191795ed63f7SArthur Kepner 19186146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 1919f9467eaeSJoe Perches pr_debug("%s: marking %s for removal\n", __func__, ifname); 192095ed63f7SArthur Kepner 192195ed63f7SArthur Kepner while (1) { 192295ed63f7SArthur Kepner 192395ed63f7SArthur Kepner pkt_dev = __pktgen_NN_threads(ifname, REMOVE); 1924222f1806SLuiz Capitulino if (pkt_dev == NULL) 1925222f1806SLuiz Capitulino break; /* success */ 192695ed63f7SArthur Kepner 19276146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 1928f9467eaeSJoe Perches pr_debug("%s: waiting for %s to disappear....\n", 1929f9467eaeSJoe Perches __func__, ifname); 193095ed63f7SArthur Kepner schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); 19316146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 193295ed63f7SArthur Kepner 193395ed63f7SArthur Kepner if (++i >= max_tries) { 1934f9467eaeSJoe Perches pr_err("%s: timed out after waiting %d msec for device %s to be removed\n", 1935f9467eaeSJoe Perches __func__, msec_per_try * i, ifname); 193695ed63f7SArthur Kepner break; 193795ed63f7SArthur Kepner } 193895ed63f7SArthur Kepner 193995ed63f7SArthur Kepner } 194095ed63f7SArthur Kepner 19416146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 194239df232fSStephen Hemminger } 194395ed63f7SArthur Kepner 194439df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev) 194539df232fSStephen Hemminger { 194639df232fSStephen Hemminger struct pktgen_thread *t; 194739df232fSStephen Hemminger 194839df232fSStephen Hemminger list_for_each_entry(t, &pktgen_threads, th_list) { 194939df232fSStephen Hemminger struct pktgen_dev *pkt_dev; 195039df232fSStephen Hemminger 195139df232fSStephen Hemminger list_for_each_entry(pkt_dev, &t->if_list, list) { 195239df232fSStephen Hemminger if (pkt_dev->odev != dev) 195339df232fSStephen Hemminger continue; 195439df232fSStephen Hemminger 195539df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 195639df232fSStephen Hemminger 19572975315bSAlexey Dobriyan pkt_dev->entry = proc_create_data(dev->name, 0600, 19582975315bSAlexey Dobriyan pg_proc_dir, 19592975315bSAlexey Dobriyan &pktgen_if_fops, 19602975315bSAlexey Dobriyan pkt_dev); 196139df232fSStephen Hemminger if (!pkt_dev->entry) 1962f9467eaeSJoe Perches pr_err("can't move proc entry for '%s'\n", 1963f9467eaeSJoe Perches dev->name); 196439df232fSStephen Hemminger break; 196539df232fSStephen Hemminger } 196639df232fSStephen Hemminger } 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds 1969222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused, 1970222f1806SLuiz Capitulino unsigned long event, void *ptr) 19711da177e4SLinus Torvalds { 197239df232fSStephen Hemminger struct net_device *dev = ptr; 19731da177e4SLinus Torvalds 1974721499e8SYOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 1975e9dc8653SEric W. Biederman return NOTIFY_DONE; 1976e9dc8653SEric W. Biederman 19771da177e4SLinus Torvalds /* It is OK that we do not hold the group lock right now, 19781da177e4SLinus Torvalds * as we run under the RTNL lock. 19791da177e4SLinus Torvalds */ 19801da177e4SLinus Torvalds 19811da177e4SLinus Torvalds switch (event) { 198239df232fSStephen Hemminger case NETDEV_CHANGENAME: 198339df232fSStephen Hemminger pktgen_change_name(dev); 19841da177e4SLinus Torvalds break; 19851da177e4SLinus Torvalds 19861da177e4SLinus Torvalds case NETDEV_UNREGISTER: 198795ed63f7SArthur Kepner pktgen_mark_device(dev->name); 19881da177e4SLinus Torvalds break; 19893ff50b79SStephen Hemminger } 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds return NOTIFY_DONE; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds 199463adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, 199563adc6fbSStephen Hemminger const char *ifname) 1996e6fce5b9SRobert Olsson { 1997e6fce5b9SRobert Olsson char b[IFNAMSIZ+5]; 1998d6182223SPaul Gortmaker int i; 1999e6fce5b9SRobert Olsson 2000e6fce5b9SRobert Olsson for (i = 0; ifname[i] != '@'; i++) { 2001e6fce5b9SRobert Olsson if (i == IFNAMSIZ) 2002e6fce5b9SRobert Olsson break; 2003e6fce5b9SRobert Olsson 2004e6fce5b9SRobert Olsson b[i] = ifname[i]; 2005e6fce5b9SRobert Olsson } 2006e6fce5b9SRobert Olsson b[i] = 0; 2007e6fce5b9SRobert Olsson 2008e6fce5b9SRobert Olsson return dev_get_by_name(&init_net, b); 2009e6fce5b9SRobert Olsson } 2010e6fce5b9SRobert Olsson 2011e6fce5b9SRobert Olsson 20121da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */ 20131da177e4SLinus Torvalds 201439df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) 2015222f1806SLuiz Capitulino { 20161da177e4SLinus Torvalds struct net_device *odev; 201739df232fSStephen Hemminger int err; 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds /* Clean old setups */ 20201da177e4SLinus Torvalds if (pkt_dev->odev) { 20211da177e4SLinus Torvalds dev_put(pkt_dev->odev); 20221da177e4SLinus Torvalds pkt_dev->odev = NULL; 20231da177e4SLinus Torvalds } 20241da177e4SLinus Torvalds 2025e6fce5b9SRobert Olsson odev = pktgen_dev_get_by_name(pkt_dev, ifname); 20261da177e4SLinus Torvalds if (!odev) { 2027f9467eaeSJoe Perches pr_err("no such netdevice: \"%s\"\n", ifname); 202839df232fSStephen Hemminger return -ENODEV; 20291da177e4SLinus Torvalds } 203039df232fSStephen Hemminger 20311da177e4SLinus Torvalds if (odev->type != ARPHRD_ETHER) { 2032f9467eaeSJoe Perches pr_err("not an ethernet device: \"%s\"\n", ifname); 203339df232fSStephen Hemminger err = -EINVAL; 203439df232fSStephen Hemminger } else if (!netif_running(odev)) { 2035f9467eaeSJoe Perches pr_err("device is down: \"%s\"\n", ifname); 203639df232fSStephen Hemminger err = -ENETDOWN; 203739df232fSStephen Hemminger } else { 20381da177e4SLinus Torvalds pkt_dev->odev = odev; 203939df232fSStephen Hemminger return 0; 204039df232fSStephen Hemminger } 20411da177e4SLinus Torvalds 20421da177e4SLinus Torvalds dev_put(odev); 204339df232fSStephen Hemminger return err; 20441da177e4SLinus Torvalds } 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev 20471da177e4SLinus Torvalds * structure to have the right information to create/send packets 20481da177e4SLinus Torvalds */ 20491da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) 20501da177e4SLinus Torvalds { 205164c00d81SAndrew Gallatin int ntxq; 205264c00d81SAndrew Gallatin 20531da177e4SLinus Torvalds if (!pkt_dev->odev) { 2054f9467eaeSJoe Perches pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n"); 2055222f1806SLuiz Capitulino sprintf(pkt_dev->result, 2056222f1806SLuiz Capitulino "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); 20571da177e4SLinus Torvalds return; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds 206064c00d81SAndrew Gallatin /* make sure that we don't pick a non-existing transmit queue */ 206164c00d81SAndrew Gallatin ntxq = pkt_dev->odev->real_num_tx_queues; 2062bfdbc0acSRobert Olsson 206364c00d81SAndrew Gallatin if (ntxq <= pkt_dev->queue_map_min) { 2064f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 206588271660SJesse Brandeburg pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, 2066593f63b0SEric Dumazet pkt_dev->odevname); 206764c00d81SAndrew Gallatin pkt_dev->queue_map_min = ntxq - 1; 206864c00d81SAndrew Gallatin } 206988271660SJesse Brandeburg if (pkt_dev->queue_map_max >= ntxq) { 2070f9467eaeSJoe Perches pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n", 207188271660SJesse Brandeburg pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, 2072593f63b0SEric Dumazet pkt_dev->odevname); 207364c00d81SAndrew Gallatin pkt_dev->queue_map_max = ntxq - 1; 207464c00d81SAndrew Gallatin } 207564c00d81SAndrew Gallatin 20761da177e4SLinus Torvalds /* Default to the interface's mac if not explicitly set. */ 20771da177e4SLinus Torvalds 2078f404e9a6SKris Katterjohn if (is_zero_ether_addr(pkt_dev->src_mac)) 2079f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds /* Set up Dest MAC */ 2082f404e9a6SKris Katterjohn memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds /* Set up pkt size */ 20851da177e4SLinus Torvalds pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) { 20881da177e4SLinus Torvalds /* 20891da177e4SLinus Torvalds * Skip this automatic address setting until locks or functions 20901da177e4SLinus Torvalds * gets exported 20911da177e4SLinus Torvalds */ 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds #ifdef NOTNOW 20941da177e4SLinus Torvalds int i, set = 0, err = 1; 20951da177e4SLinus Torvalds struct inet6_dev *idev; 20961da177e4SLinus Torvalds 20971da177e4SLinus Torvalds for (i = 0; i < IN6_ADDR_HSIZE; i++) 20981da177e4SLinus Torvalds if (pkt_dev->cur_in6_saddr.s6_addr[i]) { 20991da177e4SLinus Torvalds set = 1; 21001da177e4SLinus Torvalds break; 21011da177e4SLinus Torvalds } 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds if (!set) { 21041da177e4SLinus Torvalds 21051da177e4SLinus Torvalds /* 21061da177e4SLinus Torvalds * Use linklevel address if unconfigured. 21071da177e4SLinus Torvalds * 21081da177e4SLinus Torvalds * use ipv6_get_lladdr if/when it's get exported 21091da177e4SLinus Torvalds */ 21101da177e4SLinus Torvalds 21118814c4b5SYOSHIFUJI Hideaki rcu_read_lock(); 211263adc6fbSStephen Hemminger idev = __in6_dev_get(pkt_dev->odev); 211363adc6fbSStephen Hemminger if (idev) { 21141da177e4SLinus Torvalds struct inet6_ifaddr *ifp; 21151da177e4SLinus Torvalds 21161da177e4SLinus Torvalds read_lock_bh(&idev->lock); 2117222f1806SLuiz Capitulino for (ifp = idev->addr_list; ifp; 2118222f1806SLuiz Capitulino ifp = ifp->if_next) { 2119f64f9e71SJoe Perches if (ifp->scope == IFA_LINK && 2120f64f9e71SJoe Perches !(ifp->flags & IFA_F_TENTATIVE)) { 2121222f1806SLuiz Capitulino ipv6_addr_copy(&pkt_dev-> 2122222f1806SLuiz Capitulino cur_in6_saddr, 2123222f1806SLuiz Capitulino &ifp->addr); 21241da177e4SLinus Torvalds err = 0; 21251da177e4SLinus Torvalds break; 21261da177e4SLinus Torvalds } 21271da177e4SLinus Torvalds } 21281da177e4SLinus Torvalds read_unlock_bh(&idev->lock); 21291da177e4SLinus Torvalds } 21308814c4b5SYOSHIFUJI Hideaki rcu_read_unlock(); 2131222f1806SLuiz Capitulino if (err) 2132f9467eaeSJoe Perches pr_err("ERROR: IPv6 link address not available\n"); 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds #endif 2135222f1806SLuiz Capitulino } else { 21361da177e4SLinus Torvalds pkt_dev->saddr_min = 0; 21371da177e4SLinus Torvalds pkt_dev->saddr_max = 0; 21381da177e4SLinus Torvalds if (strlen(pkt_dev->src_min) == 0) { 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds struct in_device *in_dev; 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds rcu_read_lock(); 2143e5ed6399SHerbert Xu in_dev = __in_dev_get_rcu(pkt_dev->odev); 21441da177e4SLinus Torvalds if (in_dev) { 21451da177e4SLinus Torvalds if (in_dev->ifa_list) { 2146222f1806SLuiz Capitulino pkt_dev->saddr_min = 2147222f1806SLuiz Capitulino in_dev->ifa_list->ifa_address; 21481da177e4SLinus Torvalds pkt_dev->saddr_max = pkt_dev->saddr_min; 21491da177e4SLinus Torvalds } 21501da177e4SLinus Torvalds } 21511da177e4SLinus Torvalds rcu_read_unlock(); 2152222f1806SLuiz Capitulino } else { 21531da177e4SLinus Torvalds pkt_dev->saddr_min = in_aton(pkt_dev->src_min); 21541da177e4SLinus Torvalds pkt_dev->saddr_max = in_aton(pkt_dev->src_max); 21551da177e4SLinus Torvalds } 21561da177e4SLinus Torvalds 21571da177e4SLinus Torvalds pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); 21581da177e4SLinus Torvalds pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); 21591da177e4SLinus Torvalds } 21601da177e4SLinus Torvalds /* Initialize current values. */ 21611da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 21621da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 21631da177e4SLinus Torvalds pkt_dev->cur_saddr = pkt_dev->saddr_min; 21641da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->daddr_min; 21651da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 21661da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 21671da177e4SLinus Torvalds pkt_dev->nflows = 0; 21681da177e4SLinus Torvalds } 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds 2171fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) 2172fd29cf72SStephen Hemminger { 2173ef87979cSStephen Hemminger ktime_t start_time, end_time; 2174417bc4b8SEric Dumazet s64 remaining; 21752bc481cfSStephen Hemminger struct hrtimer_sleeper t; 2176fd29cf72SStephen Hemminger 21772bc481cfSStephen Hemminger hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 21782bc481cfSStephen Hemminger hrtimer_set_expires(&t.timer, spin_until); 2179fd29cf72SStephen Hemminger 218043d28b65SDaniel Turull remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer)); 2181417bc4b8SEric Dumazet if (remaining <= 0) { 2182417bc4b8SEric Dumazet pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 21831da177e4SLinus Torvalds return; 2184417bc4b8SEric Dumazet } 21852bc481cfSStephen Hemminger 2186ef87979cSStephen Hemminger start_time = ktime_now(); 218743d28b65SDaniel Turull if (remaining < 100000) 218843d28b65SDaniel Turull ndelay(remaining); /* really small just spin */ 21892bc481cfSStephen Hemminger else { 21902bc481cfSStephen Hemminger /* see do_nanosleep */ 21912bc481cfSStephen Hemminger hrtimer_init_sleeper(&t, current); 21922bc481cfSStephen Hemminger do { 21932bc481cfSStephen Hemminger set_current_state(TASK_INTERRUPTIBLE); 21942bc481cfSStephen Hemminger hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS); 21952bc481cfSStephen Hemminger if (!hrtimer_active(&t.timer)) 21962bc481cfSStephen Hemminger t.task = NULL; 21972bc481cfSStephen Hemminger 21982bc481cfSStephen Hemminger if (likely(t.task)) 21991da177e4SLinus Torvalds schedule(); 22001da177e4SLinus Torvalds 22012bc481cfSStephen Hemminger hrtimer_cancel(&t.timer); 22022bc481cfSStephen Hemminger } while (t.task && pkt_dev->running && !signal_pending(current)); 22032bc481cfSStephen Hemminger __set_current_state(TASK_RUNNING); 22041da177e4SLinus Torvalds } 2205ef87979cSStephen Hemminger end_time = ktime_now(); 2206ef87979cSStephen Hemminger 2207ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); 220807a0f0f0SDaniel Turull pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds 221116dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 221216dab72fSJamal Hadi Salim { 2213a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead = 0; 221416dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); 221516dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); 221616dab72fSJamal Hadi Salim pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); 221716dab72fSJamal Hadi Salim } 221816dab72fSJamal Hadi Salim 2219648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow) 2220007a531bSJamal Hadi Salim { 2221648fda74SStephen Hemminger return !!(pkt_dev->flows[flow].flags & F_INIT); 2222007a531bSJamal Hadi Salim } 2223007a531bSJamal Hadi Salim 2224007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev) 2225007a531bSJamal Hadi Salim { 2226007a531bSJamal Hadi Salim int flow = pkt_dev->curfl; 2227007a531bSJamal Hadi Salim 2228007a531bSJamal Hadi Salim if (pkt_dev->flags & F_FLOW_SEQ) { 2229007a531bSJamal Hadi Salim if (pkt_dev->flows[flow].count >= pkt_dev->lflow) { 2230007a531bSJamal Hadi Salim /* reset time */ 2231007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22321211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 2233007a531bSJamal Hadi Salim pkt_dev->curfl += 1; 2234007a531bSJamal Hadi Salim if (pkt_dev->curfl >= pkt_dev->cflows) 2235007a531bSJamal Hadi Salim pkt_dev->curfl = 0; /*reset */ 2236007a531bSJamal Hadi Salim } 2237007a531bSJamal Hadi Salim } else { 2238007a531bSJamal Hadi Salim flow = random32() % pkt_dev->cflows; 22391211a645SRobert Olsson pkt_dev->curfl = flow; 2240007a531bSJamal Hadi Salim 22411211a645SRobert Olsson if (pkt_dev->flows[flow].count > pkt_dev->lflow) { 2242007a531bSJamal Hadi Salim pkt_dev->flows[flow].count = 0; 22431211a645SRobert Olsson pkt_dev->flows[flow].flags = 0; 22441211a645SRobert Olsson } 2245007a531bSJamal Hadi Salim } 2246007a531bSJamal Hadi Salim 2247007a531bSJamal Hadi Salim return pkt_dev->curfl; 2248007a531bSJamal Hadi Salim } 2249007a531bSJamal Hadi Salim 2250a553e4a6SJamal Hadi Salim 2251a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2252a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else 2253a553e4a6SJamal Hadi Salim * we go look for it ... 2254a553e4a6SJamal Hadi Salim */ 2255bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 2256fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) 2257a553e4a6SJamal Hadi Salim { 2258a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[flow].x; 2259a553e4a6SJamal Hadi Salim if (!x) { 2260a553e4a6SJamal Hadi Salim /*slow path: we dont already have xfrm_state*/ 2261bd55775cSJamal Hadi Salim x = xfrm_stateonly_find(&init_net, DUMMY_MARK, 22625447c5e4SAlexey Dobriyan (xfrm_address_t *)&pkt_dev->cur_daddr, 2263a553e4a6SJamal Hadi Salim (xfrm_address_t *)&pkt_dev->cur_saddr, 2264a553e4a6SJamal Hadi Salim AF_INET, 2265a553e4a6SJamal Hadi Salim pkt_dev->ipsmode, 2266a553e4a6SJamal Hadi Salim pkt_dev->ipsproto, 0); 2267a553e4a6SJamal Hadi Salim if (x) { 2268a553e4a6SJamal Hadi Salim pkt_dev->flows[flow].x = x; 2269a553e4a6SJamal Hadi Salim set_pkt_overhead(pkt_dev); 2270a553e4a6SJamal Hadi Salim pkt_dev->pkt_overhead += x->props.header_len; 2271a553e4a6SJamal Hadi Salim } 2272a553e4a6SJamal Hadi Salim 2273a553e4a6SJamal Hadi Salim } 2274a553e4a6SJamal Hadi Salim } 2275a553e4a6SJamal Hadi Salim #endif 2276fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev) 2277fd2ea0a7SDavid S. Miller { 2278e6fce5b9SRobert Olsson 2279e6fce5b9SRobert Olsson if (pkt_dev->flags & F_QUEUE_MAP_CPU) 2280e6fce5b9SRobert Olsson pkt_dev->cur_queue_map = smp_processor_id(); 2281e6fce5b9SRobert Olsson 2282896a7cf8SEric Dumazet else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { 2283fd2ea0a7SDavid S. Miller __u16 t; 2284fd2ea0a7SDavid S. Miller if (pkt_dev->flags & F_QUEUE_MAP_RND) { 2285fd2ea0a7SDavid S. Miller t = random32() % 2286fd2ea0a7SDavid S. Miller (pkt_dev->queue_map_max - 2287fd2ea0a7SDavid S. Miller pkt_dev->queue_map_min + 1) 2288fd2ea0a7SDavid S. Miller + pkt_dev->queue_map_min; 2289fd2ea0a7SDavid S. Miller } else { 2290fd2ea0a7SDavid S. Miller t = pkt_dev->cur_queue_map + 1; 2291fd2ea0a7SDavid S. Miller if (t > pkt_dev->queue_map_max) 2292fd2ea0a7SDavid S. Miller t = pkt_dev->queue_map_min; 2293fd2ea0a7SDavid S. Miller } 2294fd2ea0a7SDavid S. Miller pkt_dev->cur_queue_map = t; 2295fd2ea0a7SDavid S. Miller } 2296bfdbc0acSRobert Olsson pkt_dev->cur_queue_map = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues; 2297fd2ea0a7SDavid S. Miller } 2298fd2ea0a7SDavid S. Miller 22991da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values 23001da177e4SLinus Torvalds * for IP src/dest, UDP src/dst port, MAC-Addr src/dst 23011da177e4SLinus Torvalds */ 2302222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev) 2303222f1806SLuiz Capitulino { 23041da177e4SLinus Torvalds __u32 imn; 23051da177e4SLinus Torvalds __u32 imx; 23061da177e4SLinus Torvalds int flow = 0; 23071da177e4SLinus Torvalds 2308007a531bSJamal Hadi Salim if (pkt_dev->cflows) 2309007a531bSJamal Hadi Salim flow = f_pick(pkt_dev); 23101da177e4SLinus Torvalds 23111da177e4SLinus Torvalds /* Deal with source MAC */ 23121da177e4SLinus Torvalds if (pkt_dev->src_mac_count > 1) { 23131da177e4SLinus Torvalds __u32 mc; 23141da177e4SLinus Torvalds __u32 tmp; 23151da177e4SLinus Torvalds 23161da177e4SLinus Torvalds if (pkt_dev->flags & F_MACSRC_RND) 23175fa6fc76SStephen Hemminger mc = random32() % pkt_dev->src_mac_count; 23181da177e4SLinus Torvalds else { 23191da177e4SLinus Torvalds mc = pkt_dev->cur_src_mac_offset++; 2320ff2a79a5SRobert Olsson if (pkt_dev->cur_src_mac_offset >= 2321222f1806SLuiz Capitulino pkt_dev->src_mac_count) 23221da177e4SLinus Torvalds pkt_dev->cur_src_mac_offset = 0; 23231da177e4SLinus Torvalds } 23241da177e4SLinus Torvalds 23251da177e4SLinus Torvalds tmp = pkt_dev->src_mac[5] + (mc & 0xFF); 23261da177e4SLinus Torvalds pkt_dev->hh[11] = tmp; 23271da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23281da177e4SLinus Torvalds pkt_dev->hh[10] = tmp; 23291da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23301da177e4SLinus Torvalds pkt_dev->hh[9] = tmp; 23311da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23321da177e4SLinus Torvalds pkt_dev->hh[8] = tmp; 23331da177e4SLinus Torvalds tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); 23341da177e4SLinus Torvalds pkt_dev->hh[7] = tmp; 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds /* Deal with Destination MAC */ 23381da177e4SLinus Torvalds if (pkt_dev->dst_mac_count > 1) { 23391da177e4SLinus Torvalds __u32 mc; 23401da177e4SLinus Torvalds __u32 tmp; 23411da177e4SLinus Torvalds 23421da177e4SLinus Torvalds if (pkt_dev->flags & F_MACDST_RND) 23435fa6fc76SStephen Hemminger mc = random32() % pkt_dev->dst_mac_count; 23441da177e4SLinus Torvalds 23451da177e4SLinus Torvalds else { 23461da177e4SLinus Torvalds mc = pkt_dev->cur_dst_mac_offset++; 2347ff2a79a5SRobert Olsson if (pkt_dev->cur_dst_mac_offset >= 2348222f1806SLuiz Capitulino pkt_dev->dst_mac_count) { 23491da177e4SLinus Torvalds pkt_dev->cur_dst_mac_offset = 0; 23501da177e4SLinus Torvalds } 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); 23541da177e4SLinus Torvalds pkt_dev->hh[5] = tmp; 23551da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); 23561da177e4SLinus Torvalds pkt_dev->hh[4] = tmp; 23571da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); 23581da177e4SLinus Torvalds pkt_dev->hh[3] = tmp; 23591da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); 23601da177e4SLinus Torvalds pkt_dev->hh[2] = tmp; 23611da177e4SLinus Torvalds tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); 23621da177e4SLinus Torvalds pkt_dev->hh[1] = tmp; 23631da177e4SLinus Torvalds } 23641da177e4SLinus Torvalds 2365ca6549afSSteven Whitehouse if (pkt_dev->flags & F_MPLS_RND) { 2366ca6549afSSteven Whitehouse unsigned i; 2367ca6549afSSteven Whitehouse for (i = 0; i < pkt_dev->nr_labels; i++) 2368ca6549afSSteven Whitehouse if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) 2369ca6549afSSteven Whitehouse pkt_dev->labels[i] = MPLS_STACK_BOTTOM | 23705fa6fc76SStephen Hemminger ((__force __be32)random32() & 2371ca6549afSSteven Whitehouse htonl(0x000fffff)); 2372ca6549afSSteven Whitehouse } 2373ca6549afSSteven Whitehouse 237434954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) { 23755fa6fc76SStephen Hemminger pkt_dev->vlan_id = random32() & (4096-1); 237634954ddcSFrancesco Fondelli } 237734954ddcSFrancesco Fondelli 237834954ddcSFrancesco Fondelli if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) { 23795fa6fc76SStephen Hemminger pkt_dev->svlan_id = random32() & (4096 - 1); 238034954ddcSFrancesco Fondelli } 238134954ddcSFrancesco Fondelli 23821da177e4SLinus Torvalds if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { 23831da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPSRC_RND) 23845fa6fc76SStephen Hemminger pkt_dev->cur_udp_src = random32() % 23855fa6fc76SStephen Hemminger (pkt_dev->udp_src_max - pkt_dev->udp_src_min) 23865fa6fc76SStephen Hemminger + pkt_dev->udp_src_min; 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds else { 23891da177e4SLinus Torvalds pkt_dev->cur_udp_src++; 23901da177e4SLinus Torvalds if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) 23911da177e4SLinus Torvalds pkt_dev->cur_udp_src = pkt_dev->udp_src_min; 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds } 23941da177e4SLinus Torvalds 23951da177e4SLinus Torvalds if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { 23961da177e4SLinus Torvalds if (pkt_dev->flags & F_UDPDST_RND) { 23975fa6fc76SStephen Hemminger pkt_dev->cur_udp_dst = random32() % 23985fa6fc76SStephen Hemminger (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min) 23995fa6fc76SStephen Hemminger + pkt_dev->udp_dst_min; 2400222f1806SLuiz Capitulino } else { 24011da177e4SLinus Torvalds pkt_dev->cur_udp_dst++; 24021da177e4SLinus Torvalds if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) 24031da177e4SLinus Torvalds pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; 24041da177e4SLinus Torvalds } 24051da177e4SLinus Torvalds } 24061da177e4SLinus Torvalds 24071da177e4SLinus Torvalds if (!(pkt_dev->flags & F_IPV6)) { 24081da177e4SLinus Torvalds 240963adc6fbSStephen Hemminger imn = ntohl(pkt_dev->saddr_min); 241063adc6fbSStephen Hemminger imx = ntohl(pkt_dev->saddr_max); 241163adc6fbSStephen Hemminger if (imn < imx) { 24121da177e4SLinus Torvalds __u32 t; 24131da177e4SLinus Torvalds if (pkt_dev->flags & F_IPSRC_RND) 24145fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 24151da177e4SLinus Torvalds else { 24161da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_saddr); 24171da177e4SLinus Torvalds t++; 241863adc6fbSStephen Hemminger if (t > imx) 24191da177e4SLinus Torvalds t = imn; 242063adc6fbSStephen Hemminger 24211da177e4SLinus Torvalds } 24221da177e4SLinus Torvalds pkt_dev->cur_saddr = htonl(t); 24231da177e4SLinus Torvalds } 24241da177e4SLinus Torvalds 2425007a531bSJamal Hadi Salim if (pkt_dev->cflows && f_seen(pkt_dev, flow)) { 24261da177e4SLinus Torvalds pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; 24271da177e4SLinus Torvalds } else { 2428252e3346SAl Viro imn = ntohl(pkt_dev->daddr_min); 2429252e3346SAl Viro imx = ntohl(pkt_dev->daddr_max); 2430252e3346SAl Viro if (imn < imx) { 24311da177e4SLinus Torvalds __u32 t; 2432252e3346SAl Viro __be32 s; 24331da177e4SLinus Torvalds if (pkt_dev->flags & F_IPDST_RND) { 24341da177e4SLinus Torvalds 24355fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2436252e3346SAl Viro s = htonl(t); 24371da177e4SLinus Torvalds 243821cf2253SJoe Perches while (ipv4_is_loopback(s) || 243921cf2253SJoe Perches ipv4_is_multicast(s) || 24401e637c74SJan Engelhardt ipv4_is_lbcast(s) || 244121cf2253SJoe Perches ipv4_is_zeronet(s) || 244221cf2253SJoe Perches ipv4_is_local_multicast(s)) { 24435fa6fc76SStephen Hemminger t = random32() % (imx - imn) + imn; 2444252e3346SAl Viro s = htonl(t); 24451da177e4SLinus Torvalds } 2446252e3346SAl Viro pkt_dev->cur_daddr = s; 2447252e3346SAl Viro } else { 24481da177e4SLinus Torvalds t = ntohl(pkt_dev->cur_daddr); 24491da177e4SLinus Torvalds t++; 24501da177e4SLinus Torvalds if (t > imx) { 24511da177e4SLinus Torvalds t = imn; 24521da177e4SLinus Torvalds } 24531da177e4SLinus Torvalds pkt_dev->cur_daddr = htonl(t); 24541da177e4SLinus Torvalds } 24551da177e4SLinus Torvalds } 24561da177e4SLinus Torvalds if (pkt_dev->cflows) { 2457007a531bSJamal Hadi Salim pkt_dev->flows[flow].flags |= F_INIT; 2458222f1806SLuiz Capitulino pkt_dev->flows[flow].cur_daddr = 2459222f1806SLuiz Capitulino pkt_dev->cur_daddr; 2460a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2461a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) 2462a553e4a6SJamal Hadi Salim get_ipsec_sa(pkt_dev, flow); 2463a553e4a6SJamal Hadi Salim #endif 24641da177e4SLinus Torvalds pkt_dev->nflows++; 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds } 2467222f1806SLuiz Capitulino } else { /* IPV6 * */ 2468222f1806SLuiz Capitulino 24691da177e4SLinus Torvalds if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && 24701da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && 24711da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && 24721da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; 24731da177e4SLinus Torvalds else { 24741da177e4SLinus Torvalds int i; 24751da177e4SLinus Torvalds 24761da177e4SLinus Torvalds /* Only random destinations yet */ 24771da177e4SLinus Torvalds 24781da177e4SLinus Torvalds for (i = 0; i < 4; i++) { 24791da177e4SLinus Torvalds pkt_dev->cur_in6_daddr.s6_addr32[i] = 24805fa6fc76SStephen Hemminger (((__force __be32)random32() | 24811da177e4SLinus Torvalds pkt_dev->min_in6_daddr.s6_addr32[i]) & 24821da177e4SLinus Torvalds pkt_dev->max_in6_daddr.s6_addr32[i]); 24831da177e4SLinus Torvalds } 24841da177e4SLinus Torvalds } 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds 24871da177e4SLinus Torvalds if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { 24881da177e4SLinus Torvalds __u32 t; 24891da177e4SLinus Torvalds if (pkt_dev->flags & F_TXSIZE_RND) { 24905fa6fc76SStephen Hemminger t = random32() % 24915fa6fc76SStephen Hemminger (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size) 24925fa6fc76SStephen Hemminger + pkt_dev->min_pkt_size; 2493222f1806SLuiz Capitulino } else { 24941da177e4SLinus Torvalds t = pkt_dev->cur_pkt_size + 1; 24951da177e4SLinus Torvalds if (t > pkt_dev->max_pkt_size) 24961da177e4SLinus Torvalds t = pkt_dev->min_pkt_size; 24971da177e4SLinus Torvalds } 24981da177e4SLinus Torvalds pkt_dev->cur_pkt_size = t; 24991da177e4SLinus Torvalds } 25001da177e4SLinus Torvalds 2501fd2ea0a7SDavid S. Miller set_cur_queue_map(pkt_dev); 250245b270f8SRobert Olsson 25031da177e4SLinus Torvalds pkt_dev->flows[flow].count++; 25041da177e4SLinus Torvalds } 25051da177e4SLinus Torvalds 2506a553e4a6SJamal Hadi Salim 2507a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2508a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) 2509a553e4a6SJamal Hadi Salim { 2510a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2511a553e4a6SJamal Hadi Salim int err = 0; 2512a553e4a6SJamal Hadi Salim struct iphdr *iph; 2513a553e4a6SJamal Hadi Salim 2514a553e4a6SJamal Hadi Salim if (!x) 2515a553e4a6SJamal Hadi Salim return 0; 2516a553e4a6SJamal Hadi Salim /* XXX: we dont support tunnel mode for now until 2517a553e4a6SJamal Hadi Salim * we resolve the dst issue */ 2518a553e4a6SJamal Hadi Salim if (x->props.mode != XFRM_MODE_TRANSPORT) 2519a553e4a6SJamal Hadi Salim return 0; 2520a553e4a6SJamal Hadi Salim 2521a553e4a6SJamal Hadi Salim spin_lock(&x->lock); 2522a553e4a6SJamal Hadi Salim iph = ip_hdr(skb); 2523a553e4a6SJamal Hadi Salim 252413996378SHerbert Xu err = x->outer_mode->output(x, skb); 2525a553e4a6SJamal Hadi Salim if (err) 2526a553e4a6SJamal Hadi Salim goto error; 2527a553e4a6SJamal Hadi Salim err = x->type->output(x, skb); 2528a553e4a6SJamal Hadi Salim if (err) 2529a553e4a6SJamal Hadi Salim goto error; 2530a553e4a6SJamal Hadi Salim 2531a553e4a6SJamal Hadi Salim x->curlft.bytes += skb->len; 2532a553e4a6SJamal Hadi Salim x->curlft.packets++; 2533a553e4a6SJamal Hadi Salim error: 2534a553e4a6SJamal Hadi Salim spin_unlock(&x->lock); 2535a553e4a6SJamal Hadi Salim return err; 2536a553e4a6SJamal Hadi Salim } 2537a553e4a6SJamal Hadi Salim 2538475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev) 2539a553e4a6SJamal Hadi Salim { 2540a553e4a6SJamal Hadi Salim if (pkt_dev->cflows) { 2541a553e4a6SJamal Hadi Salim /* let go of the SAs if we have them */ 2542d6182223SPaul Gortmaker int i; 2543d6182223SPaul Gortmaker for (i = 0; i < pkt_dev->cflows; i++) { 2544a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[i].x; 2545a553e4a6SJamal Hadi Salim if (x) { 2546a553e4a6SJamal Hadi Salim xfrm_state_put(x); 2547a553e4a6SJamal Hadi Salim pkt_dev->flows[i].x = NULL; 2548a553e4a6SJamal Hadi Salim } 2549a553e4a6SJamal Hadi Salim } 2550a553e4a6SJamal Hadi Salim } 2551a553e4a6SJamal Hadi Salim } 2552a553e4a6SJamal Hadi Salim 2553475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev, 2554a553e4a6SJamal Hadi Salim struct sk_buff *skb, __be16 protocol) 2555a553e4a6SJamal Hadi Salim { 2556a553e4a6SJamal Hadi Salim if (pkt_dev->flags & F_IPSEC_ON) { 2557a553e4a6SJamal Hadi Salim struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; 2558a553e4a6SJamal Hadi Salim int nhead = 0; 2559a553e4a6SJamal Hadi Salim if (x) { 2560a553e4a6SJamal Hadi Salim int ret; 2561a553e4a6SJamal Hadi Salim __u8 *eth; 2562a553e4a6SJamal Hadi Salim nhead = x->props.header_len - skb_headroom(skb); 2563a553e4a6SJamal Hadi Salim if (nhead > 0) { 2564a553e4a6SJamal Hadi Salim ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); 2565a553e4a6SJamal Hadi Salim if (ret < 0) { 2566f9467eaeSJoe Perches pr_err("Error expanding ipsec packet %d\n", 2567f9467eaeSJoe Perches ret); 2568b4bb4ac8SIlpo Järvinen goto err; 2569a553e4a6SJamal Hadi Salim } 2570a553e4a6SJamal Hadi Salim } 2571a553e4a6SJamal Hadi Salim 2572a553e4a6SJamal Hadi Salim /* ipsec is not expecting ll header */ 2573a553e4a6SJamal Hadi Salim skb_pull(skb, ETH_HLEN); 2574a553e4a6SJamal Hadi Salim ret = pktgen_output_ipsec(skb, pkt_dev); 2575a553e4a6SJamal Hadi Salim if (ret) { 2576f9467eaeSJoe Perches pr_err("Error creating ipsec packet %d\n", ret); 2577b4bb4ac8SIlpo Järvinen goto err; 2578a553e4a6SJamal Hadi Salim } 2579a553e4a6SJamal Hadi Salim /* restore ll */ 2580a553e4a6SJamal Hadi Salim eth = (__u8 *) skb_push(skb, ETH_HLEN); 2581a553e4a6SJamal Hadi Salim memcpy(eth, pkt_dev->hh, 12); 2582a553e4a6SJamal Hadi Salim *(u16 *) ð[12] = protocol; 2583a553e4a6SJamal Hadi Salim } 2584a553e4a6SJamal Hadi Salim } 2585a553e4a6SJamal Hadi Salim return 1; 2586b4bb4ac8SIlpo Järvinen err: 2587b4bb4ac8SIlpo Järvinen kfree_skb(skb); 2588b4bb4ac8SIlpo Järvinen return 0; 2589a553e4a6SJamal Hadi Salim } 2590a553e4a6SJamal Hadi Salim #endif 2591a553e4a6SJamal Hadi Salim 2592ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2593ca6549afSSteven Whitehouse { 2594ca6549afSSteven Whitehouse unsigned i; 259563adc6fbSStephen Hemminger for (i = 0; i < pkt_dev->nr_labels; i++) 2596ca6549afSSteven Whitehouse *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; 259763adc6fbSStephen Hemminger 2598ca6549afSSteven Whitehouse mpls--; 2599ca6549afSSteven Whitehouse *mpls |= MPLS_STACK_BOTTOM; 2600ca6549afSSteven Whitehouse } 2601ca6549afSSteven Whitehouse 26020f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi, 26030f37c605SAl Viro unsigned int prio) 26040f37c605SAl Viro { 26050f37c605SAl Viro return htons(id | (cfi << 12) | (prio << 13)); 26060f37c605SAl Viro } 26070f37c605SAl Viro 26081da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev, 26091da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 26101da177e4SLinus Torvalds { 26111da177e4SLinus Torvalds struct sk_buff *skb = NULL; 26121da177e4SLinus Torvalds __u8 *eth; 26131da177e4SLinus Torvalds struct udphdr *udph; 26141da177e4SLinus Torvalds int datalen, iplen; 26151da177e4SLinus Torvalds struct iphdr *iph; 26161da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2617d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IP); 2618ca6549afSSteven Whitehouse __be32 *mpls; 261934954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 262034954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 262134954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 262234954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2623fd2ea0a7SDavid S. Miller u16 queue_map; 2624ca6549afSSteven Whitehouse 2625ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2626d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 26271da177e4SLinus Torvalds 262834954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2629d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 263034954ddcSFrancesco Fondelli 263164053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 263264053beeSRobert Olsson * fields. 263364053beeSRobert Olsson */ 263464053beeSRobert Olsson mod_cur_headers(pkt_dev); 2635eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 263664053beeSRobert Olsson 26377ac5459eSDavid S. Miller datalen = (odev->hard_header_len + 16) & ~0xf; 2638e99b99b4SRobert Olsson 2639e99b99b4SRobert Olsson if (pkt_dev->flags & F_NODE) { 2640e99b99b4SRobert Olsson int node; 2641e99b99b4SRobert Olsson 2642e99b99b4SRobert Olsson if (pkt_dev->node >= 0) 2643e99b99b4SRobert Olsson node = pkt_dev->node; 2644e99b99b4SRobert Olsson else 2645e99b99b4SRobert Olsson node = numa_node_id(); 2646e99b99b4SRobert Olsson 2647e99b99b4SRobert Olsson skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64 2648e99b99b4SRobert Olsson + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node); 2649e99b99b4SRobert Olsson if (likely(skb)) { 2650e99b99b4SRobert Olsson skb_reserve(skb, NET_SKB_PAD); 2651e99b99b4SRobert Olsson skb->dev = odev; 2652e99b99b4SRobert Olsson } 2653e99b99b4SRobert Olsson } 2654e99b99b4SRobert Olsson else 2655e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 2656e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 2657e470757dSStephen Hemminger + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); 2658e99b99b4SRobert Olsson 26591da177e4SLinus Torvalds if (!skb) { 26601da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 26611da177e4SLinus Torvalds return NULL; 26621da177e4SLinus Torvalds } 26631da177e4SLinus Torvalds 26647ac5459eSDavid S. Miller skb_reserve(skb, datalen); 26651da177e4SLinus Torvalds 26661da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 26671da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 2668ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 2669ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2670ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 267134954ddcSFrancesco Fondelli 267234954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 267334954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 267434954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26750f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 26760f37c605SAl Viro pkt_dev->svlan_cfi, 26770f37c605SAl Viro pkt_dev->svlan_p); 267834954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2679d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 268034954ddcSFrancesco Fondelli } 268134954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 26820f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 26830f37c605SAl Viro pkt_dev->vlan_cfi, 26840f37c605SAl Viro pkt_dev->vlan_p); 268534954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 2686d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IP); 268734954ddcSFrancesco Fondelli } 268834954ddcSFrancesco Fondelli 268927a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 2690b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct iphdr); 2691ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2692fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 26939e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 26949e50e3acSJohn Fastabend 2695ddc7b8e3SArnaldo Carvalho de Melo iph = ip_hdr(skb); 2696ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 26971da177e4SLinus Torvalds 26981da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 2699252e3346SAl Viro *(__be16 *) & eth[12] = protocol; 27001da177e4SLinus Torvalds 2701ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 2702ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - 270316dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 27041da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) 27051da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 27061da177e4SLinus Torvalds 27071da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 27081da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 27091da177e4SLinus Torvalds udph->len = htons(datalen + 8); /* DATA + udphdr */ 27101da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 27111da177e4SLinus Torvalds 27121da177e4SLinus Torvalds iph->ihl = 5; 27131da177e4SLinus Torvalds iph->version = 4; 27141da177e4SLinus Torvalds iph->ttl = 32; 27151ca7768cSFrancesco Fondelli iph->tos = pkt_dev->tos; 27161da177e4SLinus Torvalds iph->protocol = IPPROTO_UDP; /* UDP */ 27171da177e4SLinus Torvalds iph->saddr = pkt_dev->cur_saddr; 27181da177e4SLinus Torvalds iph->daddr = pkt_dev->cur_daddr; 271966ed1e5eSEric Dumazet iph->id = htons(pkt_dev->ip_id); 272066ed1e5eSEric Dumazet pkt_dev->ip_id++; 27211da177e4SLinus Torvalds iph->frag_off = 0; 27221da177e4SLinus Torvalds iplen = 20 + 8 + datalen; 27231da177e4SLinus Torvalds iph->tot_len = htons(iplen); 27241da177e4SLinus Torvalds iph->check = 0; 27251da177e4SLinus Torvalds iph->check = ip_fast_csum((void *)iph, iph->ihl); 2726ca6549afSSteven Whitehouse skb->protocol = protocol; 2727b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 272816dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 27291da177e4SLinus Torvalds skb->dev = odev; 27301da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 27311da177e4SLinus Torvalds 273266ed1e5eSEric Dumazet if (pkt_dev->nfrags <= 0) { 27331da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 273466ed1e5eSEric Dumazet memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); 273566ed1e5eSEric Dumazet } else { 27361da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 273766ed1e5eSEric Dumazet int i, len; 27381da177e4SLinus Torvalds 27391da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 27401da177e4SLinus Torvalds 27411da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 27421da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 27431da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 274466ed1e5eSEric Dumazet len = datalen - frags * PAGE_SIZE; 274566ed1e5eSEric Dumazet memset(skb_put(skb, len), 0, len); 27461da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 27471da177e4SLinus Torvalds } 27481da177e4SLinus Torvalds 27491da177e4SLinus Torvalds i = 0; 27501da177e4SLinus Torvalds while (datalen > 0) { 275166ed1e5eSEric Dumazet struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); 27521da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 27531da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 27541da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 27551da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 27561da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 27571da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 27581da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 27591da177e4SLinus Torvalds i++; 27601da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27611da177e4SLinus Torvalds } 27621da177e4SLinus Torvalds 27631da177e4SLinus Torvalds while (i < frags) { 27641da177e4SLinus Torvalds int rem; 27651da177e4SLinus Torvalds 27661da177e4SLinus Torvalds if (i == 0) 27671da177e4SLinus Torvalds break; 27681da177e4SLinus Torvalds 27691da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 27701da177e4SLinus Torvalds if (rem == 0) 27711da177e4SLinus Torvalds break; 27721da177e4SLinus Torvalds 27731da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 27741da177e4SLinus Torvalds 2775222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 2776222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 27771da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 2778222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 2779222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 2780222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 2781222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 27821da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 27831da177e4SLinus Torvalds i++; 27841da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 27851da177e4SLinus Torvalds } 27861da177e4SLinus Torvalds } 27871da177e4SLinus Torvalds 278863adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 278963adc6fbSStephen Hemminger * convert them to network byte order 279063adc6fbSStephen Hemminger */ 27911da177e4SLinus Torvalds if (pgh) { 27921da177e4SLinus Torvalds struct timeval timestamp; 27931da177e4SLinus Torvalds 27941da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 27951da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 27961da177e4SLinus Torvalds 27971da177e4SLinus Torvalds do_gettimeofday(×tamp); 27981da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 27991da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 28001da177e4SLinus Torvalds } 28011da177e4SLinus Torvalds 2802a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 2803a553e4a6SJamal Hadi Salim if (!process_ipsec(pkt_dev, skb, protocol)) 2804a553e4a6SJamal Hadi Salim return NULL; 2805a553e4a6SJamal Hadi Salim #endif 2806a553e4a6SJamal Hadi Salim 28071da177e4SLinus Torvalds return skb; 28081da177e4SLinus Torvalds } 28091da177e4SLinus Torvalds 28101da177e4SLinus Torvalds /* 28111da177e4SLinus Torvalds * scan_ip6, fmt_ip taken from dietlibc-0.21 28121da177e4SLinus Torvalds * Author Felix von Leitner <felix-dietlibc@fefe.de> 28131da177e4SLinus Torvalds * 28141da177e4SLinus Torvalds * Slightly modified for kernel. 28151da177e4SLinus Torvalds * Should be candidate for net/ipv4/utils.c 28161da177e4SLinus Torvalds * --ro 28171da177e4SLinus Torvalds */ 28181da177e4SLinus Torvalds 28191da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]) 28201da177e4SLinus Torvalds { 28211da177e4SLinus Torvalds unsigned int i; 28221da177e4SLinus Torvalds unsigned int len = 0; 28231da177e4SLinus Torvalds unsigned long u; 28241da177e4SLinus Torvalds char suffix[16]; 28251da177e4SLinus Torvalds unsigned int prefixlen = 0; 28261da177e4SLinus Torvalds unsigned int suffixlen = 0; 2827252e3346SAl Viro __be32 tmp; 2828cfcabdccSStephen Hemminger char *pos; 28291da177e4SLinus Torvalds 2830222f1806SLuiz Capitulino for (i = 0; i < 16; i++) 2831222f1806SLuiz Capitulino ip[i] = 0; 28321da177e4SLinus Torvalds 28331da177e4SLinus Torvalds for (;;) { 28341da177e4SLinus Torvalds if (*s == ':') { 28351da177e4SLinus Torvalds len++; 28361da177e4SLinus Torvalds if (s[1] == ':') { /* Found "::", skip to part 2 */ 28371da177e4SLinus Torvalds s += 2; 28381da177e4SLinus Torvalds len++; 28391da177e4SLinus Torvalds break; 28401da177e4SLinus Torvalds } 28411da177e4SLinus Torvalds s++; 28421da177e4SLinus Torvalds } 28431da177e4SLinus Torvalds 2844cfcabdccSStephen Hemminger u = simple_strtoul(s, &pos, 16); 2845cfcabdccSStephen Hemminger i = pos - s; 2846222f1806SLuiz Capitulino if (!i) 2847222f1806SLuiz Capitulino return 0; 28481da177e4SLinus Torvalds if (prefixlen == 12 && s[i] == '.') { 28491da177e4SLinus Torvalds 28501da177e4SLinus Torvalds /* the last 4 bytes may be written as IPv4 address */ 28511da177e4SLinus Torvalds 28521da177e4SLinus Torvalds tmp = in_aton(s); 28531da177e4SLinus Torvalds memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); 28541da177e4SLinus Torvalds return i + len; 28551da177e4SLinus Torvalds } 28561da177e4SLinus Torvalds ip[prefixlen++] = (u >> 8); 28571da177e4SLinus Torvalds ip[prefixlen++] = (u & 255); 2858222f1806SLuiz Capitulino s += i; 2859222f1806SLuiz Capitulino len += i; 28601da177e4SLinus Torvalds if (prefixlen == 16) 28611da177e4SLinus Torvalds return len; 28621da177e4SLinus Torvalds } 28631da177e4SLinus Torvalds 28641da177e4SLinus Torvalds /* part 2, after "::" */ 28651da177e4SLinus Torvalds for (;;) { 28661da177e4SLinus Torvalds if (*s == ':') { 28671da177e4SLinus Torvalds if (suffixlen == 0) 28681da177e4SLinus Torvalds break; 28691da177e4SLinus Torvalds s++; 28701da177e4SLinus Torvalds len++; 28711da177e4SLinus Torvalds } else if (suffixlen != 0) 28721da177e4SLinus Torvalds break; 2873cfcabdccSStephen Hemminger 2874cfcabdccSStephen Hemminger u = simple_strtol(s, &pos, 16); 2875cfcabdccSStephen Hemminger i = pos - s; 28761da177e4SLinus Torvalds if (!i) { 2877222f1806SLuiz Capitulino if (*s) 2878222f1806SLuiz Capitulino len--; 28791da177e4SLinus Torvalds break; 28801da177e4SLinus Torvalds } 28811da177e4SLinus Torvalds if (suffixlen + prefixlen <= 12 && s[i] == '.') { 28821da177e4SLinus Torvalds tmp = in_aton(s); 2883222f1806SLuiz Capitulino memcpy((struct in_addr *)(suffix + suffixlen), &tmp, 2884222f1806SLuiz Capitulino sizeof(tmp)); 28851da177e4SLinus Torvalds suffixlen += 4; 28861da177e4SLinus Torvalds len += strlen(s); 28871da177e4SLinus Torvalds break; 28881da177e4SLinus Torvalds } 28891da177e4SLinus Torvalds suffix[suffixlen++] = (u >> 8); 28901da177e4SLinus Torvalds suffix[suffixlen++] = (u & 255); 2891222f1806SLuiz Capitulino s += i; 2892222f1806SLuiz Capitulino len += i; 28931da177e4SLinus Torvalds if (prefixlen + suffixlen == 16) 28941da177e4SLinus Torvalds break; 28951da177e4SLinus Torvalds } 28961da177e4SLinus Torvalds for (i = 0; i < suffixlen; i++) 28971da177e4SLinus Torvalds ip[16 - suffixlen + i] = suffix[i]; 28981da177e4SLinus Torvalds return len; 28991da177e4SLinus Torvalds } 29001da177e4SLinus Torvalds 2901222f1806SLuiz Capitulino static char tohex(char hexdigit) 2902222f1806SLuiz Capitulino { 29031da177e4SLinus Torvalds return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; 29041da177e4SLinus Torvalds } 29051da177e4SLinus Torvalds 2906222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i) 2907222f1806SLuiz Capitulino { 29081da177e4SLinus Torvalds char *bak = s; 2909222f1806SLuiz Capitulino *s = tohex((i >> 12) & 0xf); 2910222f1806SLuiz Capitulino if (s != bak || *s != '0') 2911222f1806SLuiz Capitulino ++s; 2912222f1806SLuiz Capitulino *s = tohex((i >> 8) & 0xf); 2913222f1806SLuiz Capitulino if (s != bak || *s != '0') 2914222f1806SLuiz Capitulino ++s; 2915222f1806SLuiz Capitulino *s = tohex((i >> 4) & 0xf); 2916222f1806SLuiz Capitulino if (s != bak || *s != '0') 2917222f1806SLuiz Capitulino ++s; 29181da177e4SLinus Torvalds *s = tohex(i & 0xf); 29191da177e4SLinus Torvalds return s - bak + 1; 29201da177e4SLinus Torvalds } 29211da177e4SLinus Torvalds 2922222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16]) 2923222f1806SLuiz Capitulino { 29241da177e4SLinus Torvalds unsigned int len; 29251da177e4SLinus Torvalds unsigned int i; 29261da177e4SLinus Torvalds unsigned int temp; 29271da177e4SLinus Torvalds unsigned int compressing; 29281da177e4SLinus Torvalds int j; 29291da177e4SLinus Torvalds 2930222f1806SLuiz Capitulino len = 0; 2931222f1806SLuiz Capitulino compressing = 0; 29321da177e4SLinus Torvalds for (j = 0; j < 16; j += 2) { 29331da177e4SLinus Torvalds 29341da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX 29351da177e4SLinus Torvalds if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { 29361da177e4SLinus Torvalds inet_ntoa_r(*(struct in_addr *)(ip + 12), s); 29371da177e4SLinus Torvalds temp = strlen(s); 29381da177e4SLinus Torvalds return len + temp; 29391da177e4SLinus Torvalds } 29401da177e4SLinus Torvalds #endif 29411da177e4SLinus Torvalds temp = ((unsigned long)(unsigned char)ip[j] << 8) + 29421da177e4SLinus Torvalds (unsigned long)(unsigned char)ip[j + 1]; 29431da177e4SLinus Torvalds if (temp == 0) { 29441da177e4SLinus Torvalds if (!compressing) { 29451da177e4SLinus Torvalds compressing = 1; 29461da177e4SLinus Torvalds if (j == 0) { 2947222f1806SLuiz Capitulino *s++ = ':'; 2948222f1806SLuiz Capitulino ++len; 29491da177e4SLinus Torvalds } 29501da177e4SLinus Torvalds } 29511da177e4SLinus Torvalds } else { 29521da177e4SLinus Torvalds if (compressing) { 29531da177e4SLinus Torvalds compressing = 0; 2954222f1806SLuiz Capitulino *s++ = ':'; 2955222f1806SLuiz Capitulino ++len; 29561da177e4SLinus Torvalds } 2957222f1806SLuiz Capitulino i = fmt_xlong(s, temp); 2958222f1806SLuiz Capitulino len += i; 2959222f1806SLuiz Capitulino s += i; 29601da177e4SLinus Torvalds if (j < 14) { 29611da177e4SLinus Torvalds *s++ = ':'; 29621da177e4SLinus Torvalds ++len; 29631da177e4SLinus Torvalds } 29641da177e4SLinus Torvalds } 29651da177e4SLinus Torvalds } 29661da177e4SLinus Torvalds if (compressing) { 2967222f1806SLuiz Capitulino *s++ = ':'; 2968222f1806SLuiz Capitulino ++len; 29691da177e4SLinus Torvalds } 29701da177e4SLinus Torvalds *s = 0; 29711da177e4SLinus Torvalds return len; 29721da177e4SLinus Torvalds } 29731da177e4SLinus Torvalds 29741da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev, 29751da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 29761da177e4SLinus Torvalds { 29771da177e4SLinus Torvalds struct sk_buff *skb = NULL; 29781da177e4SLinus Torvalds __u8 *eth; 29791da177e4SLinus Torvalds struct udphdr *udph; 29801da177e4SLinus Torvalds int datalen; 29811da177e4SLinus Torvalds struct ipv6hdr *iph; 29821da177e4SLinus Torvalds struct pktgen_hdr *pgh = NULL; 2983d5f1ce9aSStephen Hemminger __be16 protocol = htons(ETH_P_IPV6); 2984ca6549afSSteven Whitehouse __be32 *mpls; 298534954ddcSFrancesco Fondelli __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */ 298634954ddcSFrancesco Fondelli __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */ 298734954ddcSFrancesco Fondelli __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 298834954ddcSFrancesco Fondelli __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2989fd2ea0a7SDavid S. Miller u16 queue_map; 2990ca6549afSSteven Whitehouse 2991ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 2992d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_MPLS_UC); 29931da177e4SLinus Torvalds 299434954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) 2995d5f1ce9aSStephen Hemminger protocol = htons(ETH_P_8021Q); 299634954ddcSFrancesco Fondelli 299764053beeSRobert Olsson /* Update any of the values, used when we're incrementing various 299864053beeSRobert Olsson * fields. 299964053beeSRobert Olsson */ 300064053beeSRobert Olsson mod_cur_headers(pkt_dev); 3001eb589063SJunchang Wang queue_map = pkt_dev->cur_queue_map; 300264053beeSRobert Olsson 3003e470757dSStephen Hemminger skb = __netdev_alloc_skb(odev, 3004e470757dSStephen Hemminger pkt_dev->cur_pkt_size + 64 3005e470757dSStephen Hemminger + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT); 30061da177e4SLinus Torvalds if (!skb) { 30071da177e4SLinus Torvalds sprintf(pkt_dev->result, "No memory"); 30081da177e4SLinus Torvalds return NULL; 30091da177e4SLinus Torvalds } 30101da177e4SLinus Torvalds 30111da177e4SLinus Torvalds skb_reserve(skb, 16); 30121da177e4SLinus Torvalds 30131da177e4SLinus Torvalds /* Reserve for ethernet and IP header */ 30141da177e4SLinus Torvalds eth = (__u8 *) skb_push(skb, 14); 3015ca6549afSSteven Whitehouse mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); 3016ca6549afSSteven Whitehouse if (pkt_dev->nr_labels) 3017ca6549afSSteven Whitehouse mpls_push(mpls, pkt_dev); 301834954ddcSFrancesco Fondelli 301934954ddcSFrancesco Fondelli if (pkt_dev->vlan_id != 0xffff) { 302034954ddcSFrancesco Fondelli if (pkt_dev->svlan_id != 0xffff) { 302134954ddcSFrancesco Fondelli svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30220f37c605SAl Viro *svlan_tci = build_tci(pkt_dev->svlan_id, 30230f37c605SAl Viro pkt_dev->svlan_cfi, 30240f37c605SAl Viro pkt_dev->svlan_p); 302534954ddcSFrancesco Fondelli svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3026d5f1ce9aSStephen Hemminger *svlan_encapsulated_proto = htons(ETH_P_8021Q); 302734954ddcSFrancesco Fondelli } 302834954ddcSFrancesco Fondelli vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16)); 30290f37c605SAl Viro *vlan_tci = build_tci(pkt_dev->vlan_id, 30300f37c605SAl Viro pkt_dev->vlan_cfi, 30310f37c605SAl Viro pkt_dev->vlan_p); 303234954ddcSFrancesco Fondelli vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16)); 3033d5f1ce9aSStephen Hemminger *vlan_encapsulated_proto = htons(ETH_P_IPV6); 303434954ddcSFrancesco Fondelli } 303534954ddcSFrancesco Fondelli 303627a884dcSArnaldo Carvalho de Melo skb->network_header = skb->tail; 3037b0e380b1SArnaldo Carvalho de Melo skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 3038ddc7b8e3SArnaldo Carvalho de Melo skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 3039fd2ea0a7SDavid S. Miller skb_set_queue_mapping(skb, queue_map); 30409e50e3acSJohn Fastabend skb->priority = pkt_dev->skb_priority; 3041ddc7b8e3SArnaldo Carvalho de Melo iph = ipv6_hdr(skb); 3042ddc7b8e3SArnaldo Carvalho de Melo udph = udp_hdr(skb); 30431da177e4SLinus Torvalds 30441da177e4SLinus Torvalds memcpy(eth, pkt_dev->hh, 12); 3045252e3346SAl Viro *(__be16 *) ð[12] = protocol; 30461da177e4SLinus Torvalds 3047ca6549afSSteven Whitehouse /* Eth + IPh + UDPh + mpls */ 3048ca6549afSSteven Whitehouse datalen = pkt_dev->cur_pkt_size - 14 - 3049ca6549afSSteven Whitehouse sizeof(struct ipv6hdr) - sizeof(struct udphdr) - 305016dab72fSJamal Hadi Salim pkt_dev->pkt_overhead; 30511da177e4SLinus Torvalds 30521da177e4SLinus Torvalds if (datalen < sizeof(struct pktgen_hdr)) { 30531da177e4SLinus Torvalds datalen = sizeof(struct pktgen_hdr); 30541da177e4SLinus Torvalds if (net_ratelimit()) 3055f9467eaeSJoe Perches pr_info("increased datalen to %d\n", datalen); 30561da177e4SLinus Torvalds } 30571da177e4SLinus Torvalds 30581da177e4SLinus Torvalds udph->source = htons(pkt_dev->cur_udp_src); 30591da177e4SLinus Torvalds udph->dest = htons(pkt_dev->cur_udp_dst); 30601da177e4SLinus Torvalds udph->len = htons(datalen + sizeof(struct udphdr)); 30611da177e4SLinus Torvalds udph->check = 0; /* No checksum */ 30621da177e4SLinus Torvalds 3063d5f1ce9aSStephen Hemminger *(__be32 *) iph = htonl(0x60000000); /* Version + flow */ 30641da177e4SLinus Torvalds 30651ca7768cSFrancesco Fondelli if (pkt_dev->traffic_class) { 30661ca7768cSFrancesco Fondelli /* Version + traffic class + flow (0) */ 3067252e3346SAl Viro *(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20)); 30681ca7768cSFrancesco Fondelli } 30691ca7768cSFrancesco Fondelli 30701da177e4SLinus Torvalds iph->hop_limit = 32; 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds iph->payload_len = htons(sizeof(struct udphdr) + datalen); 30731da177e4SLinus Torvalds iph->nexthdr = IPPROTO_UDP; 30741da177e4SLinus Torvalds 30751da177e4SLinus Torvalds ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); 30761da177e4SLinus Torvalds ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); 30771da177e4SLinus Torvalds 3078b0e380b1SArnaldo Carvalho de Melo skb->mac_header = (skb->network_header - ETH_HLEN - 307916dab72fSJamal Hadi Salim pkt_dev->pkt_overhead); 3080ca6549afSSteven Whitehouse skb->protocol = protocol; 30811da177e4SLinus Torvalds skb->dev = odev; 30821da177e4SLinus Torvalds skb->pkt_type = PACKET_HOST; 30831da177e4SLinus Torvalds 30841da177e4SLinus Torvalds if (pkt_dev->nfrags <= 0) 30851da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)skb_put(skb, datalen); 30861da177e4SLinus Torvalds else { 30871da177e4SLinus Torvalds int frags = pkt_dev->nfrags; 30881da177e4SLinus Torvalds int i; 30891da177e4SLinus Torvalds 30901da177e4SLinus Torvalds pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); 30911da177e4SLinus Torvalds 30921da177e4SLinus Torvalds if (frags > MAX_SKB_FRAGS) 30931da177e4SLinus Torvalds frags = MAX_SKB_FRAGS; 30941da177e4SLinus Torvalds if (datalen > frags * PAGE_SIZE) { 30951da177e4SLinus Torvalds skb_put(skb, datalen - frags * PAGE_SIZE); 30961da177e4SLinus Torvalds datalen = frags * PAGE_SIZE; 30971da177e4SLinus Torvalds } 30981da177e4SLinus Torvalds 30991da177e4SLinus Torvalds i = 0; 31001da177e4SLinus Torvalds while (datalen > 0) { 31011da177e4SLinus Torvalds struct page *page = alloc_pages(GFP_KERNEL, 0); 31021da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page = page; 31031da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].page_offset = 0; 31041da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = 31051da177e4SLinus Torvalds (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); 31061da177e4SLinus Torvalds datalen -= skb_shinfo(skb)->frags[i].size; 31071da177e4SLinus Torvalds skb->len += skb_shinfo(skb)->frags[i].size; 31081da177e4SLinus Torvalds skb->data_len += skb_shinfo(skb)->frags[i].size; 31091da177e4SLinus Torvalds i++; 31101da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31111da177e4SLinus Torvalds } 31121da177e4SLinus Torvalds 31131da177e4SLinus Torvalds while (i < frags) { 31141da177e4SLinus Torvalds int rem; 31151da177e4SLinus Torvalds 31161da177e4SLinus Torvalds if (i == 0) 31171da177e4SLinus Torvalds break; 31181da177e4SLinus Torvalds 31191da177e4SLinus Torvalds rem = skb_shinfo(skb)->frags[i - 1].size / 2; 31201da177e4SLinus Torvalds if (rem == 0) 31211da177e4SLinus Torvalds break; 31221da177e4SLinus Torvalds 31231da177e4SLinus Torvalds skb_shinfo(skb)->frags[i - 1].size -= rem; 31241da177e4SLinus Torvalds 3125222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i] = 3126222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1]; 31271da177e4SLinus Torvalds get_page(skb_shinfo(skb)->frags[i].page); 3128222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page = 3129222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].page; 3130222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i].page_offset += 3131222f1806SLuiz Capitulino skb_shinfo(skb)->frags[i - 1].size; 31321da177e4SLinus Torvalds skb_shinfo(skb)->frags[i].size = rem; 31331da177e4SLinus Torvalds i++; 31341da177e4SLinus Torvalds skb_shinfo(skb)->nr_frags = i; 31351da177e4SLinus Torvalds } 31361da177e4SLinus Torvalds } 31371da177e4SLinus Torvalds 313863adc6fbSStephen Hemminger /* Stamp the time, and sequence number, 313963adc6fbSStephen Hemminger * convert them to network byte order 314063adc6fbSStephen Hemminger * should we update cloned packets too ? 314163adc6fbSStephen Hemminger */ 31421da177e4SLinus Torvalds if (pgh) { 31431da177e4SLinus Torvalds struct timeval timestamp; 31441da177e4SLinus Torvalds 31451da177e4SLinus Torvalds pgh->pgh_magic = htonl(PKTGEN_MAGIC); 31461da177e4SLinus Torvalds pgh->seq_num = htonl(pkt_dev->seq_num); 31471da177e4SLinus Torvalds 31481da177e4SLinus Torvalds do_gettimeofday(×tamp); 31491da177e4SLinus Torvalds pgh->tv_sec = htonl(timestamp.tv_sec); 31501da177e4SLinus Torvalds pgh->tv_usec = htonl(timestamp.tv_usec); 31511da177e4SLinus Torvalds } 315234954ddcSFrancesco Fondelli /* pkt_dev->seq_num++; FF: you really mean this? */ 31531da177e4SLinus Torvalds 31541da177e4SLinus Torvalds return skb; 31551da177e4SLinus Torvalds } 31561da177e4SLinus Torvalds 3157475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev, 31581da177e4SLinus Torvalds struct pktgen_dev *pkt_dev) 31591da177e4SLinus Torvalds { 31601da177e4SLinus Torvalds if (pkt_dev->flags & F_IPV6) 31611da177e4SLinus Torvalds return fill_packet_ipv6(odev, pkt_dev); 31621da177e4SLinus Torvalds else 31631da177e4SLinus Torvalds return fill_packet_ipv4(odev, pkt_dev); 31641da177e4SLinus Torvalds } 31651da177e4SLinus Torvalds 31661da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) 31671da177e4SLinus Torvalds { 31681da177e4SLinus Torvalds pkt_dev->seq_num = 1; 31691da177e4SLinus Torvalds pkt_dev->idle_acc = 0; 31701da177e4SLinus Torvalds pkt_dev->sofar = 0; 31711da177e4SLinus Torvalds pkt_dev->tx_bytes = 0; 31721da177e4SLinus Torvalds pkt_dev->errors = 0; 31731da177e4SLinus Torvalds } 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */ 31761da177e4SLinus Torvalds 31771da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t) 31781da177e4SLinus Torvalds { 3179c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 31801da177e4SLinus Torvalds int started = 0; 31811da177e4SLinus Torvalds 3182f9467eaeSJoe Perches func_enter(); 31831da177e4SLinus Torvalds 31841da177e4SLinus Torvalds if_lock(t); 3185c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 31861da177e4SLinus Torvalds 31871da177e4SLinus Torvalds /* 31881da177e4SLinus Torvalds * setup odev and create initial packet. 31891da177e4SLinus Torvalds */ 31901da177e4SLinus Torvalds pktgen_setup_inject(pkt_dev); 31911da177e4SLinus Torvalds 31921da177e4SLinus Torvalds if (pkt_dev->odev) { 31931da177e4SLinus Torvalds pktgen_clear_counters(pkt_dev); 31941da177e4SLinus Torvalds pkt_dev->running = 1; /* Cranke yeself! */ 31951da177e4SLinus Torvalds pkt_dev->skb = NULL; 3196fd29cf72SStephen Hemminger pkt_dev->started_at = 3197fd29cf72SStephen Hemminger pkt_dev->next_tx = ktime_now(); 3198fd29cf72SStephen Hemminger 319916dab72fSJamal Hadi Salim set_pkt_overhead(pkt_dev); 32001da177e4SLinus Torvalds 32011da177e4SLinus Torvalds strcpy(pkt_dev->result, "Starting"); 32021da177e4SLinus Torvalds started++; 3203222f1806SLuiz Capitulino } else 32041da177e4SLinus Torvalds strcpy(pkt_dev->result, "Error starting"); 32051da177e4SLinus Torvalds } 32061da177e4SLinus Torvalds if_unlock(t); 3207222f1806SLuiz Capitulino if (started) 3208222f1806SLuiz Capitulino t->control &= ~(T_STOP); 32091da177e4SLinus Torvalds } 32101da177e4SLinus Torvalds 32111da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void) 32121da177e4SLinus Torvalds { 3213cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32141da177e4SLinus Torvalds 3215f9467eaeSJoe Perches func_enter(); 32161da177e4SLinus Torvalds 32176146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3218cdcdbe0bSLuiz Capitulino 3219cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 322095ed63f7SArthur Kepner t->control |= T_STOP; 3221cdcdbe0bSLuiz Capitulino 32226146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32231da177e4SLinus Torvalds } 32241da177e4SLinus Torvalds 3225648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t) 32261da177e4SLinus Torvalds { 3227648fda74SStephen Hemminger const struct pktgen_dev *pkt_dev; 32281da177e4SLinus Torvalds 3229c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) 3230648fda74SStephen Hemminger if (pkt_dev->running) 3231648fda74SStephen Hemminger return 1; 3232648fda74SStephen Hemminger return 0; 32331da177e4SLinus Torvalds } 32341da177e4SLinus Torvalds 32351da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t) 32361da177e4SLinus Torvalds { 32371da177e4SLinus Torvalds if_lock(t); 32381da177e4SLinus Torvalds 32391da177e4SLinus Torvalds while (thread_is_running(t)) { 32401da177e4SLinus Torvalds 32411da177e4SLinus Torvalds if_unlock(t); 32421da177e4SLinus Torvalds 32431da177e4SLinus Torvalds msleep_interruptible(100); 32441da177e4SLinus Torvalds 32451da177e4SLinus Torvalds if (signal_pending(current)) 32461da177e4SLinus Torvalds goto signal; 32471da177e4SLinus Torvalds if_lock(t); 32481da177e4SLinus Torvalds } 32491da177e4SLinus Torvalds if_unlock(t); 32501da177e4SLinus Torvalds return 1; 32511da177e4SLinus Torvalds signal: 32521da177e4SLinus Torvalds return 0; 32531da177e4SLinus Torvalds } 32541da177e4SLinus Torvalds 32551da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void) 32561da177e4SLinus Torvalds { 3257cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32581da177e4SLinus Torvalds int sig = 1; 32591da177e4SLinus Torvalds 32606146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 3261cdcdbe0bSLuiz Capitulino 3262cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) { 32631da177e4SLinus Torvalds sig = pktgen_wait_thread_run(t); 3264222f1806SLuiz Capitulino if (sig == 0) 3265222f1806SLuiz Capitulino break; 32661da177e4SLinus Torvalds } 3267cdcdbe0bSLuiz Capitulino 3268cdcdbe0bSLuiz Capitulino if (sig == 0) 3269cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32701da177e4SLinus Torvalds t->control |= (T_STOP); 3271cdcdbe0bSLuiz Capitulino 32726146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32731da177e4SLinus Torvalds return sig; 32741da177e4SLinus Torvalds } 32751da177e4SLinus Torvalds 32761da177e4SLinus Torvalds static void pktgen_run_all_threads(void) 32771da177e4SLinus Torvalds { 3278cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 32791da177e4SLinus Torvalds 3280f9467eaeSJoe Perches func_enter(); 32811da177e4SLinus Torvalds 32826146e6a4SLuiz Capitulino mutex_lock(&pktgen_thread_lock); 32831da177e4SLinus Torvalds 3284cdcdbe0bSLuiz Capitulino list_for_each_entry(t, &pktgen_threads, th_list) 32851da177e4SLinus Torvalds t->control |= (T_RUN); 3286cdcdbe0bSLuiz Capitulino 32876146e6a4SLuiz Capitulino mutex_unlock(&pktgen_thread_lock); 32881da177e4SLinus Torvalds 328963adc6fbSStephen Hemminger /* Propagate thread->control */ 329063adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 32911da177e4SLinus Torvalds 32921da177e4SLinus Torvalds pktgen_wait_all_threads_run(); 32931da177e4SLinus Torvalds } 32941da177e4SLinus Torvalds 3295eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void) 3296eb37b41cSJesse Brandeburg { 3297eb37b41cSJesse Brandeburg struct pktgen_thread *t; 3298eb37b41cSJesse Brandeburg 3299f9467eaeSJoe Perches func_enter(); 3300eb37b41cSJesse Brandeburg 3301eb37b41cSJesse Brandeburg mutex_lock(&pktgen_thread_lock); 3302eb37b41cSJesse Brandeburg 3303eb37b41cSJesse Brandeburg list_for_each_entry(t, &pktgen_threads, th_list) 3304eb37b41cSJesse Brandeburg t->control |= (T_REMDEVALL); 3305eb37b41cSJesse Brandeburg 3306eb37b41cSJesse Brandeburg mutex_unlock(&pktgen_thread_lock); 3307eb37b41cSJesse Brandeburg 330863adc6fbSStephen Hemminger /* Propagate thread->control */ 330963adc6fbSStephen Hemminger schedule_timeout_interruptible(msecs_to_jiffies(125)); 3310eb37b41cSJesse Brandeburg 3311eb37b41cSJesse Brandeburg pktgen_wait_all_threads_run(); 3312eb37b41cSJesse Brandeburg } 3313eb37b41cSJesse Brandeburg 33141da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) 33151da177e4SLinus Torvalds { 3316fd29cf72SStephen Hemminger __u64 bps, mbps, pps; 33171da177e4SLinus Torvalds char *p = pkt_dev->result; 3318fd29cf72SStephen Hemminger ktime_t elapsed = ktime_sub(pkt_dev->stopped_at, 3319fd29cf72SStephen Hemminger pkt_dev->started_at); 3320fd29cf72SStephen Hemminger ktime_t idle = ns_to_ktime(pkt_dev->idle_acc); 33211da177e4SLinus Torvalds 3322fd29cf72SStephen Hemminger p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n", 3323fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(elapsed), 3324fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)), 3325fd29cf72SStephen Hemminger (unsigned long long)ktime_to_us(idle), 33261da177e4SLinus Torvalds (unsigned long long)pkt_dev->sofar, 33271da177e4SLinus Torvalds pkt_dev->cur_pkt_size, nr_frags); 33281da177e4SLinus Torvalds 3329fd29cf72SStephen Hemminger pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC, 3330fd29cf72SStephen Hemminger ktime_to_ns(elapsed)); 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds bps = pps * 8 * pkt_dev->cur_pkt_size; 33331da177e4SLinus Torvalds 33341da177e4SLinus Torvalds mbps = bps; 33351da177e4SLinus Torvalds do_div(mbps, 1000000); 33361da177e4SLinus Torvalds p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", 33371da177e4SLinus Torvalds (unsigned long long)pps, 33381da177e4SLinus Torvalds (unsigned long long)mbps, 33391da177e4SLinus Torvalds (unsigned long long)bps, 33401da177e4SLinus Torvalds (unsigned long long)pkt_dev->errors); 33411da177e4SLinus Torvalds } 33421da177e4SLinus Torvalds 33431da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */ 33441da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev) 33451da177e4SLinus Torvalds { 3346222f1806SLuiz Capitulino int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; 33471da177e4SLinus Torvalds 33481da177e4SLinus Torvalds if (!pkt_dev->running) { 3349f9467eaeSJoe Perches pr_warning("interface: %s is already stopped\n", 3350f9467eaeSJoe Perches pkt_dev->odevname); 33511da177e4SLinus Torvalds return -EINVAL; 33521da177e4SLinus Torvalds } 33531da177e4SLinus Torvalds 33543bda06a3SStephen Hemminger kfree_skb(pkt_dev->skb); 33553bda06a3SStephen Hemminger pkt_dev->skb = NULL; 3356fd29cf72SStephen Hemminger pkt_dev->stopped_at = ktime_now(); 33571da177e4SLinus Torvalds pkt_dev->running = 0; 33581da177e4SLinus Torvalds 335995ed63f7SArthur Kepner show_results(pkt_dev, nr_frags); 33601da177e4SLinus Torvalds 33611da177e4SLinus Torvalds return 0; 33621da177e4SLinus Torvalds } 33631da177e4SLinus Torvalds 33641da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t) 33651da177e4SLinus Torvalds { 3366c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev, *best = NULL; 33671da177e4SLinus Torvalds 33681da177e4SLinus Torvalds if_lock(t); 33691da177e4SLinus Torvalds 3370c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3371c26a8016SLuiz Capitulino if (!pkt_dev->running) 3372222f1806SLuiz Capitulino continue; 3373222f1806SLuiz Capitulino if (best == NULL) 3374c26a8016SLuiz Capitulino best = pkt_dev; 3375fd29cf72SStephen Hemminger else if (ktime_lt(pkt_dev->next_tx, best->next_tx)) 3376c26a8016SLuiz Capitulino best = pkt_dev; 33771da177e4SLinus Torvalds } 33781da177e4SLinus Torvalds if_unlock(t); 33791da177e4SLinus Torvalds return best; 33801da177e4SLinus Torvalds } 33811da177e4SLinus Torvalds 3382222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t) 3383222f1806SLuiz Capitulino { 3384c26a8016SLuiz Capitulino struct pktgen_dev *pkt_dev; 33851da177e4SLinus Torvalds 3386f9467eaeSJoe Perches func_enter(); 33871da177e4SLinus Torvalds 33881da177e4SLinus Torvalds if_lock(t); 33891da177e4SLinus Torvalds 3390c26a8016SLuiz Capitulino list_for_each_entry(pkt_dev, &t->if_list, list) { 3391c26a8016SLuiz Capitulino pktgen_stop_device(pkt_dev); 339295ed63f7SArthur Kepner } 339395ed63f7SArthur Kepner 339495ed63f7SArthur Kepner if_unlock(t); 339595ed63f7SArthur Kepner } 339695ed63f7SArthur Kepner 339795ed63f7SArthur Kepner /* 339895ed63f7SArthur Kepner * one of our devices needs to be removed - find it 339995ed63f7SArthur Kepner * and remove it 340095ed63f7SArthur Kepner */ 340195ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t) 340295ed63f7SArthur Kepner { 3403c26a8016SLuiz Capitulino struct list_head *q, *n; 3404c26a8016SLuiz Capitulino struct pktgen_dev *cur; 340595ed63f7SArthur Kepner 3406f9467eaeSJoe Perches func_enter(); 340795ed63f7SArthur Kepner 340895ed63f7SArthur Kepner if_lock(t); 340995ed63f7SArthur Kepner 3410c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3411c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 341295ed63f7SArthur Kepner 3413222f1806SLuiz Capitulino if (!cur->removal_mark) 3414222f1806SLuiz Capitulino continue; 341595ed63f7SArthur Kepner 341695ed63f7SArthur Kepner kfree_skb(cur->skb); 341795ed63f7SArthur Kepner cur->skb = NULL; 341895ed63f7SArthur Kepner 341995ed63f7SArthur Kepner pktgen_remove_device(t, cur); 342095ed63f7SArthur Kepner 342195ed63f7SArthur Kepner break; 342295ed63f7SArthur Kepner } 34231da177e4SLinus Torvalds 34241da177e4SLinus Torvalds if_unlock(t); 34251da177e4SLinus Torvalds } 34261da177e4SLinus Torvalds 34271da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t) 34281da177e4SLinus Torvalds { 3429c26a8016SLuiz Capitulino struct list_head *q, *n; 3430c26a8016SLuiz Capitulino struct pktgen_dev *cur; 34311da177e4SLinus Torvalds 3432f9467eaeSJoe Perches func_enter(); 3433f9467eaeSJoe Perches 34341da177e4SLinus Torvalds /* Remove all devices, free mem */ 34351da177e4SLinus Torvalds 34361da177e4SLinus Torvalds if_lock(t); 34371da177e4SLinus Torvalds 3438c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3439c26a8016SLuiz Capitulino cur = list_entry(q, struct pktgen_dev, list); 344095ed63f7SArthur Kepner 344195ed63f7SArthur Kepner kfree_skb(cur->skb); 344295ed63f7SArthur Kepner cur->skb = NULL; 344395ed63f7SArthur Kepner 34441da177e4SLinus Torvalds pktgen_remove_device(t, cur); 34451da177e4SLinus Torvalds } 34461da177e4SLinus Torvalds 34471da177e4SLinus Torvalds if_unlock(t); 34481da177e4SLinus Torvalds } 34491da177e4SLinus Torvalds 34501da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t) 34511da177e4SLinus Torvalds { 34521da177e4SLinus Torvalds /* Remove from the thread list */ 34531da177e4SLinus Torvalds 3454ee74baa7SDavid S. Miller remove_proc_entry(t->tsk->comm, pg_proc_dir); 34551da177e4SLinus Torvalds 34561da177e4SLinus Torvalds } 34571da177e4SLinus Torvalds 3458ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev) 34593791decbSStephen Hemminger { 3460fd29cf72SStephen Hemminger ktime_t idle_start = ktime_now(); 34613791decbSStephen Hemminger schedule(); 3462fd29cf72SStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 34633791decbSStephen Hemminger } 34643791decbSStephen Hemminger 3465ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev) 3466ef87979cSStephen Hemminger { 3467ef87979cSStephen Hemminger ktime_t idle_start = ktime_now(); 3468ef87979cSStephen Hemminger 3469ef87979cSStephen Hemminger while (atomic_read(&(pkt_dev->skb->users)) != 1) { 3470ef87979cSStephen Hemminger if (signal_pending(current)) 3471ef87979cSStephen Hemminger break; 3472ef87979cSStephen Hemminger 3473ef87979cSStephen Hemminger if (need_resched()) 3474ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3475ef87979cSStephen Hemminger else 3476ef87979cSStephen Hemminger cpu_relax(); 3477ef87979cSStephen Hemminger } 3478ef87979cSStephen Hemminger pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start)); 3479ef87979cSStephen Hemminger } 3480fd29cf72SStephen Hemminger 3481475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev) 34821da177e4SLinus Torvalds { 348300829823SStephen Hemminger struct net_device *odev = pkt_dev->odev; 34846fef4c0cSStephen Hemminger netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *) 348500829823SStephen Hemminger = odev->netdev_ops->ndo_start_xmit; 3486fd2ea0a7SDavid S. Miller struct netdev_queue *txq; 3487fd2ea0a7SDavid S. Miller u16 queue_map; 34881da177e4SLinus Torvalds int ret; 34891da177e4SLinus Torvalds 3490ef87979cSStephen Hemminger /* If device is offline, then don't send */ 3491ef87979cSStephen Hemminger if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) { 34921da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 34933791decbSStephen Hemminger return; 34941da177e4SLinus Torvalds } 34951da177e4SLinus Torvalds 3496ef87979cSStephen Hemminger /* This is max DELAY, this has special meaning of 3497ef87979cSStephen Hemminger * "never transmit" 3498ef87979cSStephen Hemminger */ 3499ef87979cSStephen Hemminger if (unlikely(pkt_dev->delay == ULLONG_MAX)) { 3500ef87979cSStephen Hemminger pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX); 3501ef87979cSStephen Hemminger return; 3502ef87979cSStephen Hemminger } 3503ef87979cSStephen Hemminger 3504ef87979cSStephen Hemminger /* If no skb or clone count exhausted then get new one */ 35057d7bb1cfSStephen Hemminger if (!pkt_dev->skb || (pkt_dev->last_ok && 35067d7bb1cfSStephen Hemminger ++pkt_dev->clone_count >= pkt_dev->clone_skb)) { 35071da177e4SLinus Torvalds /* build a new pkt */ 35081da177e4SLinus Torvalds kfree_skb(pkt_dev->skb); 35091da177e4SLinus Torvalds 35101da177e4SLinus Torvalds pkt_dev->skb = fill_packet(odev, pkt_dev); 35111da177e4SLinus Torvalds if (pkt_dev->skb == NULL) { 3512f9467eaeSJoe Perches pr_err("ERROR: couldn't allocate skb in fill_packet\n"); 35131da177e4SLinus Torvalds schedule(); 35141da177e4SLinus Torvalds pkt_dev->clone_count--; /* back out increment, OOM */ 35153791decbSStephen Hemminger return; 35161da177e4SLinus Torvalds } 3517baac8564SEric Dumazet pkt_dev->last_pkt_size = pkt_dev->skb->len; 35181da177e4SLinus Torvalds pkt_dev->allocated_skbs++; 35191da177e4SLinus Torvalds pkt_dev->clone_count = 0; /* reset counter */ 35201da177e4SLinus Torvalds } 35211da177e4SLinus Torvalds 3522ef87979cSStephen Hemminger if (pkt_dev->delay && pkt_dev->last_ok) 3523ef87979cSStephen Hemminger spin(pkt_dev, pkt_dev->next_tx); 3524ef87979cSStephen Hemminger 3525fd2ea0a7SDavid S. Miller queue_map = skb_get_queue_mapping(pkt_dev->skb); 3526fd2ea0a7SDavid S. Miller txq = netdev_get_tx_queue(odev, queue_map); 3527fd2ea0a7SDavid S. Miller 3528fd2ea0a7SDavid S. Miller __netif_tx_lock_bh(txq); 35295b8db2f5SStephen Hemminger 3530*5a0d2268SEric Dumazet if (unlikely(netif_tx_queue_frozen_or_stopped(txq))) { 3531ef87979cSStephen Hemminger ret = NETDEV_TX_BUSY; 35320835acfeSEric Dumazet pkt_dev->last_ok = 0; 35330835acfeSEric Dumazet goto unlock; 35340835acfeSEric Dumazet } 35350835acfeSEric Dumazet atomic_inc(&(pkt_dev->skb->users)); 353600829823SStephen Hemminger ret = (*xmit)(pkt_dev->skb, odev); 3537ef87979cSStephen Hemminger 35385b8db2f5SStephen Hemminger switch (ret) { 35395b8db2f5SStephen Hemminger case NETDEV_TX_OK: 354008baf561SEric Dumazet txq_trans_update(txq); 35411da177e4SLinus Torvalds pkt_dev->last_ok = 1; 35421da177e4SLinus Torvalds pkt_dev->sofar++; 35431da177e4SLinus Torvalds pkt_dev->seq_num++; 3544baac8564SEric Dumazet pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 35455b8db2f5SStephen Hemminger break; 3546f466dba1SJohn Fastabend case NET_XMIT_DROP: 3547f466dba1SJohn Fastabend case NET_XMIT_CN: 3548f466dba1SJohn Fastabend case NET_XMIT_POLICED: 3549f466dba1SJohn Fastabend /* skb has been consumed */ 3550f466dba1SJohn Fastabend pkt_dev->errors++; 3551f466dba1SJohn Fastabend break; 35525b8db2f5SStephen Hemminger default: /* Drivers are not supposed to return other values! */ 35535b8db2f5SStephen Hemminger if (net_ratelimit()) 35545b8db2f5SStephen Hemminger pr_info("pktgen: %s xmit error: %d\n", 3555593f63b0SEric Dumazet pkt_dev->odevname, ret); 35561da177e4SLinus Torvalds pkt_dev->errors++; 35575b8db2f5SStephen Hemminger /* fallthru */ 3558ef87979cSStephen Hemminger case NETDEV_TX_LOCKED: 35595b8db2f5SStephen Hemminger case NETDEV_TX_BUSY: 35605b8db2f5SStephen Hemminger /* Retry it next time */ 35615b8db2f5SStephen Hemminger atomic_dec(&(pkt_dev->skb->users)); 35621da177e4SLinus Torvalds pkt_dev->last_ok = 0; 35631da177e4SLinus Torvalds } 35640835acfeSEric Dumazet unlock: 3565fd2ea0a7SDavid S. Miller __netif_tx_unlock_bh(txq); 35661da177e4SLinus Torvalds 35671da177e4SLinus Torvalds /* If pkt_dev->count is zero, then run forever */ 35681da177e4SLinus Torvalds if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { 3569ef87979cSStephen Hemminger pktgen_wait_for_skb(pkt_dev); 35701da177e4SLinus Torvalds 35711da177e4SLinus Torvalds /* Done with this */ 35721da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 35731da177e4SLinus Torvalds } 35741da177e4SLinus Torvalds } 35751da177e4SLinus Torvalds 35761da177e4SLinus Torvalds /* 35771da177e4SLinus Torvalds * Main loop of the thread goes here 35781da177e4SLinus Torvalds */ 35791da177e4SLinus Torvalds 3580ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg) 35811da177e4SLinus Torvalds { 35821da177e4SLinus Torvalds DEFINE_WAIT(wait); 3583ee74baa7SDavid S. Miller struct pktgen_thread *t = arg; 35841da177e4SLinus Torvalds struct pktgen_dev *pkt_dev = NULL; 35851da177e4SLinus Torvalds int cpu = t->cpu; 35861da177e4SLinus Torvalds 3587ee74baa7SDavid S. Miller BUG_ON(smp_processor_id() != cpu); 35881da177e4SLinus Torvalds 35891da177e4SLinus Torvalds init_waitqueue_head(&t->queue); 3590d3ede327SDenis V. Lunev complete(&t->start_done); 35911da177e4SLinus Torvalds 3592f9467eaeSJoe Perches pr_debug("starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current)); 35931da177e4SLinus Torvalds 3594ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 35951da177e4SLinus Torvalds 359683144186SRafael J. Wysocki set_freezable(); 359783144186SRafael J. Wysocki 3598ee74baa7SDavid S. Miller while (!kthread_should_stop()) { 3599ee74baa7SDavid S. Miller pkt_dev = next_to_run(t); 3600ee74baa7SDavid S. Miller 3601ef87979cSStephen Hemminger if (unlikely(!pkt_dev && t->control == 0)) { 3602551eaff1SEric Dumazet if (pktgen_exiting) 3603551eaff1SEric Dumazet break; 3604ef87979cSStephen Hemminger wait_event_interruptible_timeout(t->queue, 3605ef87979cSStephen Hemminger t->control != 0, 3606ef87979cSStephen Hemminger HZ/10); 36071b3f720bSRafael J. Wysocki try_to_freeze(); 3608ef87979cSStephen Hemminger continue; 3609ee74baa7SDavid S. Miller } 36101da177e4SLinus Torvalds 36111da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 36121da177e4SLinus Torvalds 3613ef87979cSStephen Hemminger if (likely(pkt_dev)) { 36141da177e4SLinus Torvalds pktgen_xmit(pkt_dev); 36151da177e4SLinus Torvalds 3616ef87979cSStephen Hemminger if (need_resched()) 3617ef87979cSStephen Hemminger pktgen_resched(pkt_dev); 3618ef87979cSStephen Hemminger else 3619ef87979cSStephen Hemminger cpu_relax(); 3620ef87979cSStephen Hemminger } 3621ef87979cSStephen Hemminger 36221da177e4SLinus Torvalds if (t->control & T_STOP) { 36231da177e4SLinus Torvalds pktgen_stop(t); 36241da177e4SLinus Torvalds t->control &= ~(T_STOP); 36251da177e4SLinus Torvalds } 36261da177e4SLinus Torvalds 36271da177e4SLinus Torvalds if (t->control & T_RUN) { 36281da177e4SLinus Torvalds pktgen_run(t); 36291da177e4SLinus Torvalds t->control &= ~(T_RUN); 36301da177e4SLinus Torvalds } 36311da177e4SLinus Torvalds 363295ed63f7SArthur Kepner if (t->control & T_REMDEVALL) { 36331da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 363495ed63f7SArthur Kepner t->control &= ~(T_REMDEVALL); 363595ed63f7SArthur Kepner } 363695ed63f7SArthur Kepner 363795ed63f7SArthur Kepner if (t->control & T_REMDEV) { 363895ed63f7SArthur Kepner pktgen_rem_one_if(t); 36391da177e4SLinus Torvalds t->control &= ~(T_REMDEV); 36401da177e4SLinus Torvalds } 36411da177e4SLinus Torvalds 364209fe3ef4SAndrew Morton try_to_freeze(); 364309fe3ef4SAndrew Morton 3644ee74baa7SDavid S. Miller set_current_state(TASK_INTERRUPTIBLE); 36451da177e4SLinus Torvalds } 36461da177e4SLinus Torvalds 3647f9467eaeSJoe Perches pr_debug("%s stopping all device\n", t->tsk->comm); 36481da177e4SLinus Torvalds pktgen_stop(t); 36491da177e4SLinus Torvalds 3650f9467eaeSJoe Perches pr_debug("%s removing all device\n", t->tsk->comm); 36511da177e4SLinus Torvalds pktgen_rem_all_ifs(t); 36521da177e4SLinus Torvalds 3653f9467eaeSJoe Perches pr_debug("%s removing thread\n", t->tsk->comm); 36541da177e4SLinus Torvalds pktgen_rem_thread(t); 3655cdcdbe0bSLuiz Capitulino 3656551eaff1SEric Dumazet /* Wait for kthread_stop */ 3657551eaff1SEric Dumazet while (!kthread_should_stop()) { 3658551eaff1SEric Dumazet set_current_state(TASK_INTERRUPTIBLE); 3659551eaff1SEric Dumazet schedule(); 3660551eaff1SEric Dumazet } 3661551eaff1SEric Dumazet __set_current_state(TASK_RUNNING); 3662551eaff1SEric Dumazet 3663ee74baa7SDavid S. Miller return 0; 36641da177e4SLinus Torvalds } 36651da177e4SLinus Torvalds 3666222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 36673e984840SEric Dumazet const char *ifname, bool exact) 36681da177e4SLinus Torvalds { 3669c26a8016SLuiz Capitulino struct pktgen_dev *p, *pkt_dev = NULL; 36703e984840SEric Dumazet size_t len = strlen(ifname); 36711da177e4SLinus Torvalds 36723e984840SEric Dumazet if_lock(t); 3673c26a8016SLuiz Capitulino list_for_each_entry(p, &t->if_list, list) 36743e984840SEric Dumazet if (strncmp(p->odevname, ifname, len) == 0) { 36753e984840SEric Dumazet if (p->odevname[len]) { 36763e984840SEric Dumazet if (exact || p->odevname[len] != '@') 36773e984840SEric Dumazet continue; 36783e984840SEric Dumazet } 3679c26a8016SLuiz Capitulino pkt_dev = p; 36801da177e4SLinus Torvalds break; 36811da177e4SLinus Torvalds } 36821da177e4SLinus Torvalds 36831da177e4SLinus Torvalds if_unlock(t); 3684f9467eaeSJoe Perches pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev); 36851da177e4SLinus Torvalds return pkt_dev; 36861da177e4SLinus Torvalds } 36871da177e4SLinus Torvalds 36881da177e4SLinus Torvalds /* 36891da177e4SLinus Torvalds * Adds a dev at front of if_list. 36901da177e4SLinus Torvalds */ 36911da177e4SLinus Torvalds 3692222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t, 3693222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 36941da177e4SLinus Torvalds { 36951da177e4SLinus Torvalds int rv = 0; 36961da177e4SLinus Torvalds 36971da177e4SLinus Torvalds if_lock(t); 36981da177e4SLinus Torvalds 36991da177e4SLinus Torvalds if (pkt_dev->pg_thread) { 3700f9467eaeSJoe Perches pr_err("ERROR: already assigned to a thread\n"); 37011da177e4SLinus Torvalds rv = -EBUSY; 37021da177e4SLinus Torvalds goto out; 37031da177e4SLinus Torvalds } 3704c26a8016SLuiz Capitulino 3705c26a8016SLuiz Capitulino list_add(&pkt_dev->list, &t->if_list); 37061da177e4SLinus Torvalds pkt_dev->pg_thread = t; 37071da177e4SLinus Torvalds pkt_dev->running = 0; 37081da177e4SLinus Torvalds 37091da177e4SLinus Torvalds out: 37101da177e4SLinus Torvalds if_unlock(t); 37111da177e4SLinus Torvalds return rv; 37121da177e4SLinus Torvalds } 37131da177e4SLinus Torvalds 37141da177e4SLinus Torvalds /* Called under thread lock */ 37151da177e4SLinus Torvalds 37161da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) 37171da177e4SLinus Torvalds { 37181da177e4SLinus Torvalds struct pktgen_dev *pkt_dev; 371939df232fSStephen Hemminger int err; 37203291b9dbSEric Dumazet int node = cpu_to_node(t->cpu); 37211da177e4SLinus Torvalds 37221da177e4SLinus Torvalds /* We don't allow a device to be on several threads */ 37231da177e4SLinus Torvalds 3724d50a6b56SStephen Hemminger pkt_dev = __pktgen_NN_threads(ifname, FIND); 3725d50a6b56SStephen Hemminger if (pkt_dev) { 3726f9467eaeSJoe Perches pr_err("ERROR: interface already used\n"); 3727d50a6b56SStephen Hemminger return -EBUSY; 3728d50a6b56SStephen Hemminger } 37291da177e4SLinus Torvalds 37303291b9dbSEric Dumazet pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node); 37311da177e4SLinus Torvalds if (!pkt_dev) 37321da177e4SLinus Torvalds return -ENOMEM; 37331da177e4SLinus Torvalds 3734593f63b0SEric Dumazet strcpy(pkt_dev->odevname, ifname); 37353291b9dbSEric Dumazet pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state), 37363291b9dbSEric Dumazet node); 37371da177e4SLinus Torvalds if (pkt_dev->flows == NULL) { 37381da177e4SLinus Torvalds kfree(pkt_dev); 37391da177e4SLinus Torvalds return -ENOMEM; 37401da177e4SLinus Torvalds } 37411da177e4SLinus Torvalds memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); 37421da177e4SLinus Torvalds 374395ed63f7SArthur Kepner pkt_dev->removal_mark = 0; 37441da177e4SLinus Torvalds pkt_dev->min_pkt_size = ETH_ZLEN; 37451da177e4SLinus Torvalds pkt_dev->max_pkt_size = ETH_ZLEN; 37461da177e4SLinus Torvalds pkt_dev->nfrags = 0; 37471da177e4SLinus Torvalds pkt_dev->clone_skb = pg_clone_skb_d; 3748fd29cf72SStephen Hemminger pkt_dev->delay = pg_delay_d; 37491da177e4SLinus Torvalds pkt_dev->count = pg_count_d; 37501da177e4SLinus Torvalds pkt_dev->sofar = 0; 37511da177e4SLinus Torvalds pkt_dev->udp_src_min = 9; /* sink port */ 37521da177e4SLinus Torvalds pkt_dev->udp_src_max = 9; 37531da177e4SLinus Torvalds pkt_dev->udp_dst_min = 9; 37541da177e4SLinus Torvalds pkt_dev->udp_dst_max = 9; 37551da177e4SLinus Torvalds 375634954ddcSFrancesco Fondelli pkt_dev->vlan_p = 0; 375734954ddcSFrancesco Fondelli pkt_dev->vlan_cfi = 0; 375834954ddcSFrancesco Fondelli pkt_dev->vlan_id = 0xffff; 375934954ddcSFrancesco Fondelli pkt_dev->svlan_p = 0; 376034954ddcSFrancesco Fondelli pkt_dev->svlan_cfi = 0; 376134954ddcSFrancesco Fondelli pkt_dev->svlan_id = 0xffff; 3762e99b99b4SRobert Olsson pkt_dev->node = -1; 376334954ddcSFrancesco Fondelli 376439df232fSStephen Hemminger err = pktgen_setup_dev(pkt_dev, ifname); 376539df232fSStephen Hemminger if (err) 376639df232fSStephen Hemminger goto out1; 37671da177e4SLinus Torvalds 37685efdccbcSDenis V. Lunev pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir, 37695efdccbcSDenis V. Lunev &pktgen_if_fops, pkt_dev); 377039df232fSStephen Hemminger if (!pkt_dev->entry) { 3771f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3772d50a6b56SStephen Hemminger PG_PROC_DIR, ifname); 377339df232fSStephen Hemminger err = -EINVAL; 377439df232fSStephen Hemminger goto out2; 377539df232fSStephen Hemminger } 3776a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3777a553e4a6SJamal Hadi Salim pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; 3778a553e4a6SJamal Hadi Salim pkt_dev->ipsproto = IPPROTO_ESP; 3779a553e4a6SJamal Hadi Salim #endif 378039df232fSStephen Hemminger 378139df232fSStephen Hemminger return add_dev_to_thread(t, pkt_dev); 378239df232fSStephen Hemminger out2: 378339df232fSStephen Hemminger dev_put(pkt_dev->odev); 378439df232fSStephen Hemminger out1: 3785a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3786a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3787a553e4a6SJamal Hadi Salim #endif 37881da177e4SLinus Torvalds vfree(pkt_dev->flows); 37891da177e4SLinus Torvalds kfree(pkt_dev); 379039df232fSStephen Hemminger return err; 37911da177e4SLinus Torvalds } 37921da177e4SLinus Torvalds 3793ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu) 37941da177e4SLinus Torvalds { 3795cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3796d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3797ee74baa7SDavid S. Miller struct task_struct *p; 37981da177e4SLinus Torvalds 37993291b9dbSEric Dumazet t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL, 38003291b9dbSEric Dumazet cpu_to_node(cpu)); 38011da177e4SLinus Torvalds if (!t) { 3802f9467eaeSJoe Perches pr_err("ERROR: out of memory, can't create new thread\n"); 38031da177e4SLinus Torvalds return -ENOMEM; 38041da177e4SLinus Torvalds } 38051da177e4SLinus Torvalds 38061da177e4SLinus Torvalds spin_lock_init(&t->if_lock); 38071da177e4SLinus Torvalds t->cpu = cpu; 38081da177e4SLinus Torvalds 3809ee74baa7SDavid S. Miller INIT_LIST_HEAD(&t->if_list); 3810ee74baa7SDavid S. Miller 3811ee74baa7SDavid S. Miller list_add_tail(&t->th_list, &pktgen_threads); 3812d3ede327SDenis V. Lunev init_completion(&t->start_done); 3813ee74baa7SDavid S. Miller 3814ee74baa7SDavid S. Miller p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu); 3815ee74baa7SDavid S. Miller if (IS_ERR(p)) { 3816f9467eaeSJoe Perches pr_err("kernel_thread() failed for cpu %d\n", t->cpu); 3817ee74baa7SDavid S. Miller list_del(&t->th_list); 3818ee74baa7SDavid S. Miller kfree(t); 3819ee74baa7SDavid S. Miller return PTR_ERR(p); 3820ee74baa7SDavid S. Miller } 3821ee74baa7SDavid S. Miller kthread_bind(p, cpu); 3822ee74baa7SDavid S. Miller t->tsk = p; 3823ee74baa7SDavid S. Miller 38245efdccbcSDenis V. Lunev pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir, 38255efdccbcSDenis V. Lunev &pktgen_thread_fops, t); 3826d50a6b56SStephen Hemminger if (!pe) { 3827f9467eaeSJoe Perches pr_err("cannot create %s/%s procfs entry\n", 3828ee74baa7SDavid S. Miller PG_PROC_DIR, t->tsk->comm); 3829ee74baa7SDavid S. Miller kthread_stop(p); 3830ee74baa7SDavid S. Miller list_del(&t->th_list); 38311da177e4SLinus Torvalds kfree(t); 38321da177e4SLinus Torvalds return -EINVAL; 38331da177e4SLinus Torvalds } 3834d50a6b56SStephen Hemminger 3835ee74baa7SDavid S. Miller wake_up_process(p); 3836d3ede327SDenis V. Lunev wait_for_completion(&t->start_done); 38371da177e4SLinus Torvalds 38381da177e4SLinus Torvalds return 0; 38391da177e4SLinus Torvalds } 38401da177e4SLinus Torvalds 38411da177e4SLinus Torvalds /* 38421da177e4SLinus Torvalds * Removes a device from the thread if_list. 38431da177e4SLinus Torvalds */ 3844222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t, 3845222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38461da177e4SLinus Torvalds { 3847c26a8016SLuiz Capitulino struct list_head *q, *n; 3848c26a8016SLuiz Capitulino struct pktgen_dev *p; 38491da177e4SLinus Torvalds 3850c26a8016SLuiz Capitulino list_for_each_safe(q, n, &t->if_list) { 3851c26a8016SLuiz Capitulino p = list_entry(q, struct pktgen_dev, list); 3852c26a8016SLuiz Capitulino if (p == pkt_dev) 3853c26a8016SLuiz Capitulino list_del(&p->list); 38541da177e4SLinus Torvalds } 38551da177e4SLinus Torvalds } 38561da177e4SLinus Torvalds 3857222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t, 3858222f1806SLuiz Capitulino struct pktgen_dev *pkt_dev) 38591da177e4SLinus Torvalds { 38601da177e4SLinus Torvalds 3861f9467eaeSJoe Perches pr_debug("remove_device pkt_dev=%p\n", pkt_dev); 38621da177e4SLinus Torvalds 38631da177e4SLinus Torvalds if (pkt_dev->running) { 3864f9467eaeSJoe Perches pr_warning("WARNING: trying to remove a running interface, stopping it now\n"); 38651da177e4SLinus Torvalds pktgen_stop_device(pkt_dev); 38661da177e4SLinus Torvalds } 38671da177e4SLinus Torvalds 38681da177e4SLinus Torvalds /* Dis-associate from the interface */ 38691da177e4SLinus Torvalds 38701da177e4SLinus Torvalds if (pkt_dev->odev) { 38711da177e4SLinus Torvalds dev_put(pkt_dev->odev); 38721da177e4SLinus Torvalds pkt_dev->odev = NULL; 38731da177e4SLinus Torvalds } 38741da177e4SLinus Torvalds 38751da177e4SLinus Torvalds /* And update the thread if_list */ 38761da177e4SLinus Torvalds 38771da177e4SLinus Torvalds _rem_dev_from_if_list(t, pkt_dev); 38781da177e4SLinus Torvalds 387939df232fSStephen Hemminger if (pkt_dev->entry) 388039df232fSStephen Hemminger remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); 38811da177e4SLinus Torvalds 3882a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM 3883a553e4a6SJamal Hadi Salim free_SAs(pkt_dev); 3884a553e4a6SJamal Hadi Salim #endif 38851da177e4SLinus Torvalds vfree(pkt_dev->flows); 38861da177e4SLinus Torvalds kfree(pkt_dev); 38871da177e4SLinus Torvalds return 0; 38881da177e4SLinus Torvalds } 38891da177e4SLinus Torvalds 38901da177e4SLinus Torvalds static int __init pg_init(void) 38911da177e4SLinus Torvalds { 38921da177e4SLinus Torvalds int cpu; 3893d50a6b56SStephen Hemminger struct proc_dir_entry *pe; 3894d50a6b56SStephen Hemminger 3895f9467eaeSJoe Perches pr_info("%s", version); 38961da177e4SLinus Torvalds 3897457c4cbcSEric W. Biederman pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); 3898d50a6b56SStephen Hemminger if (!pg_proc_dir) 3899d50a6b56SStephen Hemminger return -ENODEV; 39001da177e4SLinus Torvalds 390125296d59SWang Chen pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); 3902d50a6b56SStephen Hemminger if (pe == NULL) { 3903f9467eaeSJoe Perches pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); 3904457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39051da177e4SLinus Torvalds return -EINVAL; 39061da177e4SLinus Torvalds } 39071da177e4SLinus Torvalds 39081da177e4SLinus Torvalds /* Register us to receive netdevice events */ 39091da177e4SLinus Torvalds register_netdevice_notifier(&pktgen_notifier_block); 39101da177e4SLinus Torvalds 3911670c02c2SJohn Hawkes for_each_online_cpu(cpu) { 39128024bb24SLuiz Capitulino int err; 39131da177e4SLinus Torvalds 3914ee74baa7SDavid S. Miller err = pktgen_create_thread(cpu); 39158024bb24SLuiz Capitulino if (err) 3916f9467eaeSJoe Perches pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n", 3917f9467eaeSJoe Perches cpu, err); 39181da177e4SLinus Torvalds } 39198024bb24SLuiz Capitulino 39208024bb24SLuiz Capitulino if (list_empty(&pktgen_threads)) { 3921f9467eaeSJoe Perches pr_err("ERROR: Initialization failed for all threads\n"); 39228024bb24SLuiz Capitulino unregister_netdevice_notifier(&pktgen_notifier_block); 39238024bb24SLuiz Capitulino remove_proc_entry(PGCTRL, pg_proc_dir); 3924457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39258024bb24SLuiz Capitulino return -ENODEV; 39268024bb24SLuiz Capitulino } 39278024bb24SLuiz Capitulino 39281da177e4SLinus Torvalds return 0; 39291da177e4SLinus Torvalds } 39301da177e4SLinus Torvalds 39311da177e4SLinus Torvalds static void __exit pg_cleanup(void) 39321da177e4SLinus Torvalds { 3933cdcdbe0bSLuiz Capitulino struct pktgen_thread *t; 3934cdcdbe0bSLuiz Capitulino struct list_head *q, *n; 39351da177e4SLinus Torvalds 39361da177e4SLinus Torvalds /* Stop all interfaces & threads */ 3937551eaff1SEric Dumazet pktgen_exiting = true; 39381da177e4SLinus Torvalds 3939cdcdbe0bSLuiz Capitulino list_for_each_safe(q, n, &pktgen_threads) { 3940cdcdbe0bSLuiz Capitulino t = list_entry(q, struct pktgen_thread, th_list); 3941ee74baa7SDavid S. Miller kthread_stop(t->tsk); 3942ee74baa7SDavid S. Miller kfree(t); 39431da177e4SLinus Torvalds } 39441da177e4SLinus Torvalds 39451da177e4SLinus Torvalds /* Un-register us from receiving netdevice events */ 39461da177e4SLinus Torvalds unregister_netdevice_notifier(&pktgen_notifier_block); 39471da177e4SLinus Torvalds 39481da177e4SLinus Torvalds /* Clean up proc file system */ 3949d50a6b56SStephen Hemminger remove_proc_entry(PGCTRL, pg_proc_dir); 3950457c4cbcSEric W. Biederman proc_net_remove(&init_net, PG_PROC_DIR); 39511da177e4SLinus Torvalds } 39521da177e4SLinus Torvalds 39531da177e4SLinus Torvalds module_init(pg_init); 39541da177e4SLinus Torvalds module_exit(pg_cleanup); 39551da177e4SLinus Torvalds 3956c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>"); 39571da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool"); 39581da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3959c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION); 39601da177e4SLinus Torvalds module_param(pg_count_d, int, 0); 3961c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject"); 39621da177e4SLinus Torvalds module_param(pg_delay_d, int, 0); 3963c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)"); 39641da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0); 3965c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet"); 39661da177e4SLinus Torvalds module_param(debug, int, 0); 3967c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module"); 3968