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