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