xref: /openbmc/linux/net/core/pktgen.c (revision 448d7b5daf043d109df98e3e8f8deb165c2e8896)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Authors:
31da177e4SLinus Torvalds  * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
41da177e4SLinus Torvalds  *                             Uppsala University and
51da177e4SLinus Torvalds  *                             Swedish University of Agricultural Sciences
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
81da177e4SLinus Torvalds  * Ben Greear <greearb@candelatech.com>
996de0e25SJan Engelhardt  * Jens Låås <jens.laas@data.slu.se>
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
121da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
131da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
141da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * A tool for loading the network with preconfigurated packets.
181da177e4SLinus Torvalds  * The tool is implemented as a linux module.  Parameters are output
191da177e4SLinus Torvalds  * device, delay (to hard_xmit), number of packets, and whether
201da177e4SLinus Torvalds  * to use multiple SKBs or just the same one.
211da177e4SLinus Torvalds  * pktgen uses the installed interface's output routine.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * Additional hacking by:
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * Jens.Laas@data.slu.se
261da177e4SLinus Torvalds  * Improved by ANK. 010120.
271da177e4SLinus Torvalds  * Improved by ANK even more. 010212.
281da177e4SLinus Torvalds  * MAC address typo fixed. 010417 --ro
291da177e4SLinus Torvalds  * Integrated.  020301 --DaveM
301da177e4SLinus Torvalds  * Added multiskb option 020301 --DaveM
311da177e4SLinus Torvalds  * Scaling of results. 020417--sigurdur@linpro.no
321da177e4SLinus Torvalds  * Significant re-work of the module:
331da177e4SLinus Torvalds  *   *  Convert to threaded model to more efficiently be able to transmit
341da177e4SLinus Torvalds  *       and receive on multiple interfaces at once.
351da177e4SLinus Torvalds  *   *  Converted many counters to __u64 to allow longer runs.
361da177e4SLinus Torvalds  *   *  Allow configuration of ranges, like min/max IP address, MACs,
371da177e4SLinus Torvalds  *       and UDP-ports, for both source and destination, and can
381da177e4SLinus Torvalds  *       set to use a random distribution or sequentially walk the range.
391da177e4SLinus Torvalds  *   *  Can now change most values after starting.
401da177e4SLinus Torvalds  *   *  Place 12-byte packet in UDP payload with magic number,
411da177e4SLinus Torvalds  *       sequence number, and timestamp.
421da177e4SLinus Torvalds  *   *  Add receiver code that detects dropped pkts, re-ordered pkts, and
431da177e4SLinus Torvalds  *       latencies (with micro-second) precision.
441da177e4SLinus Torvalds  *   *  Add IOCTL interface to easily get counters & configuration.
451da177e4SLinus Torvalds  *   --Ben Greear <greearb@candelatech.com>
461da177e4SLinus Torvalds  *
471da177e4SLinus Torvalds  * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
481da177e4SLinus Torvalds  * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
491da177e4SLinus Torvalds  * as a "fastpath" with a configurable number of clones after alloc's.
501da177e4SLinus Torvalds  * clone_skb=0 means all packets are allocated this also means ranges time
511da177e4SLinus Torvalds  * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
521da177e4SLinus Torvalds  * clones.
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  * Also moved to /proc/net/pktgen/
551da177e4SLinus Torvalds  * --ro
561da177e4SLinus Torvalds  *
571da177e4SLinus Torvalds  * Sept 10:  Fixed threading/locking.  Lots of bone-headed and more clever
581da177e4SLinus Torvalds  *    mistakes.  Also merged in DaveM's patch in the -pre6 patch.
591da177e4SLinus Torvalds  * --Ben Greear <greearb@candelatech.com>
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
621da177e4SLinus Torvalds  *
631da177e4SLinus Torvalds  *
641da177e4SLinus Torvalds  * 021124 Finished major redesign and rewrite for new functionality.
651da177e4SLinus Torvalds  * See Documentation/networking/pktgen.txt for how to use this.
661da177e4SLinus Torvalds  *
671da177e4SLinus Torvalds  * The new operation:
681da177e4SLinus Torvalds  * For each CPU one thread/process is created at start. This process checks
691da177e4SLinus Torvalds  * for running devices in the if_list and sends packets until count is 0 it
701da177e4SLinus Torvalds  * also the thread checks the thread->control which is used for inter-process
711da177e4SLinus Torvalds  * communication. controlling process "posts" operations to the threads this
721da177e4SLinus Torvalds  * way. The if_lock should be possible to remove when add/rem_device is merged
731da177e4SLinus Torvalds  * into this too.
741da177e4SLinus Torvalds  *
751da177e4SLinus Torvalds  * By design there should only be *one* "controlling" process. In practice
761da177e4SLinus Torvalds  * multiple write accesses gives unpredictable result. Understood by "write"
771da177e4SLinus Torvalds  * to /proc gives result code thats should be read be the "writer".
78b4099fabSStephen Hemminger  * For practical use this should be no problem.
791da177e4SLinus Torvalds  *
801da177e4SLinus Torvalds  * Note when adding devices to a specific CPU there good idea to also assign
811da177e4SLinus Torvalds  * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
821da177e4SLinus Torvalds  * --ro
831da177e4SLinus Torvalds  *
841da177e4SLinus Torvalds  * Fix refcount off by one if first packet fails, potential null deref,
851da177e4SLinus Torvalds  * memleak 030710- KJP
861da177e4SLinus Torvalds  *
871da177e4SLinus Torvalds  * First "ranges" functionality for ipv6 030726 --ro
881da177e4SLinus Torvalds  *
891da177e4SLinus Torvalds  * Included flow support. 030802 ANK.
901da177e4SLinus Torvalds  *
911da177e4SLinus Torvalds  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
921da177e4SLinus Torvalds  *
931da177e4SLinus Torvalds  * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
941da177e4SLinus Torvalds  * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
951da177e4SLinus Torvalds  *
961da177e4SLinus Torvalds  * New xmit() return, do_div and misc clean up by Stephen Hemminger
971da177e4SLinus Torvalds  * <shemminger@osdl.org> 040923
981da177e4SLinus Torvalds  *
99b4099fabSStephen Hemminger  * Randy Dunlap fixed u64 printk compiler waring
1001da177e4SLinus Torvalds  *
1011da177e4SLinus Torvalds  * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
1021da177e4SLinus Torvalds  * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
1031da177e4SLinus Torvalds  *
1041da177e4SLinus Torvalds  * Corrections from Nikolai Malykh (nmalykh@bilim.com)
1051da177e4SLinus Torvalds  * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
1061da177e4SLinus Torvalds  *
1071da177e4SLinus Torvalds  * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
1081da177e4SLinus Torvalds  * 050103
109ca6549afSSteven Whitehouse  *
110ca6549afSSteven Whitehouse  * MPLS support by Steven Whitehouse <steve@chygwyn.com>
111ca6549afSSteven Whitehouse  *
11234954ddcSFrancesco Fondelli  * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
11334954ddcSFrancesco Fondelli  *
114ce5d0b47SAdit Ranadive  * Fixed src_mac command to set source mac of packet to value specified in
115ce5d0b47SAdit Ranadive  * command by Adit Ranadive <adit.262@gmail.com>
116ce5d0b47SAdit Ranadive  *
1171da177e4SLinus Torvalds  */
118f9467eaeSJoe Perches 
119f9467eaeSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
120f9467eaeSJoe Perches 
1211da177e4SLinus Torvalds #include <linux/sys.h>
1221da177e4SLinus Torvalds #include <linux/types.h>
1231da177e4SLinus Torvalds #include <linux/module.h>
1241da177e4SLinus Torvalds #include <linux/moduleparam.h>
1251da177e4SLinus Torvalds #include <linux/kernel.h>
126222fa076SLuiz Capitulino #include <linux/mutex.h>
1271da177e4SLinus Torvalds #include <linux/sched.h>
1281da177e4SLinus Torvalds #include <linux/slab.h>
1291da177e4SLinus Torvalds #include <linux/vmalloc.h>
1301da177e4SLinus Torvalds #include <linux/unistd.h>
1311da177e4SLinus Torvalds #include <linux/string.h>
1321da177e4SLinus Torvalds #include <linux/ptrace.h>
1331da177e4SLinus Torvalds #include <linux/errno.h>
1341da177e4SLinus Torvalds #include <linux/ioport.h>
1351da177e4SLinus Torvalds #include <linux/interrupt.h>
1364fc268d2SRandy Dunlap #include <linux/capability.h>
1372bc481cfSStephen Hemminger #include <linux/hrtimer.h>
13809fe3ef4SAndrew Morton #include <linux/freezer.h>
1391da177e4SLinus Torvalds #include <linux/delay.h>
1401da177e4SLinus Torvalds #include <linux/timer.h>
141cdcdbe0bSLuiz Capitulino #include <linux/list.h>
1421da177e4SLinus Torvalds #include <linux/init.h>
1431da177e4SLinus Torvalds #include <linux/skbuff.h>
1441da177e4SLinus Torvalds #include <linux/netdevice.h>
1451da177e4SLinus Torvalds #include <linux/inet.h>
1461da177e4SLinus Torvalds #include <linux/inetdevice.h>
1471da177e4SLinus Torvalds #include <linux/rtnetlink.h>
1481da177e4SLinus Torvalds #include <linux/if_arp.h>
14934954ddcSFrancesco Fondelli #include <linux/if_vlan.h>
1501da177e4SLinus Torvalds #include <linux/in.h>
1511da177e4SLinus Torvalds #include <linux/ip.h>
1521da177e4SLinus Torvalds #include <linux/ipv6.h>
1531da177e4SLinus Torvalds #include <linux/udp.h>
1541da177e4SLinus Torvalds #include <linux/proc_fs.h>
155d50a6b56SStephen Hemminger #include <linux/seq_file.h>
1561da177e4SLinus Torvalds #include <linux/wait.h>
157f404e9a6SKris Katterjohn #include <linux/etherdevice.h>
158ee74baa7SDavid S. Miller #include <linux/kthread.h>
159457c4cbcSEric W. Biederman #include <net/net_namespace.h>
1601da177e4SLinus Torvalds #include <net/checksum.h>
1611da177e4SLinus Torvalds #include <net/ipv6.h>
1621da177e4SLinus Torvalds #include <net/addrconf.h>
163a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
164a553e4a6SJamal Hadi Salim #include <net/xfrm.h>
165a553e4a6SJamal Hadi Salim #endif
1661da177e4SLinus Torvalds #include <asm/byteorder.h>
1671da177e4SLinus Torvalds #include <linux/rcupdate.h>
1681977f032SJiri Slaby #include <linux/bitops.h>
16963adc6fbSStephen Hemminger #include <linux/io.h>
17063adc6fbSStephen Hemminger #include <linux/timex.h>
17163adc6fbSStephen Hemminger #include <linux/uaccess.h>
1721da177e4SLinus Torvalds #include <asm/dma.h>
1731da177e4SLinus Torvalds #include <asm/div64.h>		/* do_div */
1741da177e4SLinus Torvalds 
17543d28b65SDaniel Turull #define VERSION	"2.74"
1761da177e4SLinus Torvalds #define IP_NAME_SZ 32
177ca6549afSSteven Whitehouse #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
178d5f1ce9aSStephen Hemminger #define MPLS_STACK_BOTTOM htonl(0x00000100)
1791da177e4SLinus Torvalds 
180f9467eaeSJoe Perches #define func_enter() pr_debug("entering %s\n", __func__);
181f9467eaeSJoe Perches 
1821da177e4SLinus Torvalds /* Device flag bits */
1831da177e4SLinus Torvalds #define F_IPSRC_RND   (1<<0)	/* IP-Src Random  */
1841da177e4SLinus Torvalds #define F_IPDST_RND   (1<<1)	/* IP-Dst Random  */
1851da177e4SLinus Torvalds #define F_UDPSRC_RND  (1<<2)	/* UDP-Src Random */
1861da177e4SLinus Torvalds #define F_UDPDST_RND  (1<<3)	/* UDP-Dst Random */
1871da177e4SLinus Torvalds #define F_MACSRC_RND  (1<<4)	/* MAC-Src Random */
1881da177e4SLinus Torvalds #define F_MACDST_RND  (1<<5)	/* MAC-Dst Random */
1891da177e4SLinus Torvalds #define F_TXSIZE_RND  (1<<6)	/* Transmit size is random */
1901da177e4SLinus Torvalds #define F_IPV6        (1<<7)	/* Interface in IPV6 Mode */
191ca6549afSSteven Whitehouse #define F_MPLS_RND    (1<<8)	/* Random MPLS labels */
19234954ddcSFrancesco Fondelli #define F_VID_RND     (1<<9)	/* Random VLAN ID */
19334954ddcSFrancesco Fondelli #define F_SVID_RND    (1<<10)	/* Random SVLAN ID */
194007a531bSJamal Hadi Salim #define F_FLOW_SEQ    (1<<11)	/* Sequential flows */
195a553e4a6SJamal Hadi Salim #define F_IPSEC_ON    (1<<12)	/* ipsec on for flows */
19645b270f8SRobert Olsson #define F_QUEUE_MAP_RND (1<<13)	/* queue map Random */
197e6fce5b9SRobert Olsson #define F_QUEUE_MAP_CPU (1<<14)	/* queue map mirrors smp_processor_id() */
198e99b99b4SRobert Olsson #define F_NODE          (1<<15)	/* Node memory alloc*/
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds /* Thread control flag bits */
2016b80d6a6SStephen Hemminger #define T_STOP        (1<<0)	/* Stop run */
2026b80d6a6SStephen Hemminger #define T_RUN         (1<<1)	/* Start run */
2036b80d6a6SStephen Hemminger #define T_REMDEVALL   (1<<2)	/* Remove all devs */
2046b80d6a6SStephen Hemminger #define T_REMDEV      (1<<3)	/* Remove one dev */
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds /* If lock -- can be removed after some work */
2071da177e4SLinus Torvalds #define   if_lock(t)           spin_lock(&(t->if_lock));
2081da177e4SLinus Torvalds #define   if_unlock(t)           spin_unlock(&(t->if_lock));
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /* Used to help with determining the pkts on receive */
2111da177e4SLinus Torvalds #define PKTGEN_MAGIC 0xbe9be955
212d50a6b56SStephen Hemminger #define PG_PROC_DIR "pktgen"
213d50a6b56SStephen Hemminger #define PGCTRL	    "pgctrl"
21463adc6fbSStephen Hemminger static struct proc_dir_entry *pg_proc_dir;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds #define MAX_CFLOWS  65536
2171da177e4SLinus Torvalds 
21834954ddcSFrancesco Fondelli #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
21934954ddcSFrancesco Fondelli #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
22034954ddcSFrancesco Fondelli 
221222f1806SLuiz Capitulino struct flow_state {
222252e3346SAl Viro 	__be32 cur_daddr;
2231da177e4SLinus Torvalds 	int count;
224a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
225a553e4a6SJamal Hadi Salim 	struct xfrm_state *x;
226a553e4a6SJamal Hadi Salim #endif
227007a531bSJamal Hadi Salim 	__u32 flags;
2281da177e4SLinus Torvalds };
2291da177e4SLinus Torvalds 
230007a531bSJamal Hadi Salim /* flow flag bits */
231007a531bSJamal Hadi Salim #define F_INIT   (1<<0)		/* flow has been initialized */
232007a531bSJamal Hadi Salim 
2331da177e4SLinus Torvalds struct pktgen_dev {
2341da177e4SLinus Torvalds 	/*
2351da177e4SLinus Torvalds 	 * Try to keep frequent/infrequent used vars. separated.
2361da177e4SLinus Torvalds 	 */
23739df232fSStephen Hemminger 	struct proc_dir_entry *entry;	/* proc file */
2381da177e4SLinus Torvalds 	struct pktgen_thread *pg_thread;/* the owner */
23963adc6fbSStephen Hemminger 	struct list_head list;		/* chaining in the thread's run-queue */
2401da177e4SLinus Torvalds 
24163adc6fbSStephen Hemminger 	int running;		/* if false, the test will stop */
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	/* If min != max, then we will either do a linear iteration, or
2441da177e4SLinus Torvalds 	 * we will do a random selection from within the range.
2451da177e4SLinus Torvalds 	 */
2461da177e4SLinus Torvalds 	__u32 flags;
24795ed63f7SArthur Kepner 	int removal_mark;	/* non-zero => the device is marked for
24895ed63f7SArthur Kepner 				 * removal by worker thread */
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	int min_pkt_size;	/* = ETH_ZLEN; */
2511da177e4SLinus Torvalds 	int max_pkt_size;	/* = ETH_ZLEN; */
25216dab72fSJamal Hadi Salim 	int pkt_overhead;	/* overhead for MPLS, VLANs, IPSEC etc */
2531da177e4SLinus Torvalds 	int nfrags;
254fd29cf72SStephen Hemminger 	u64 delay;		/* nano-seconds */
255fd29cf72SStephen Hemminger 
2561da177e4SLinus Torvalds 	__u64 count;		/* Default No packets to send */
2571da177e4SLinus Torvalds 	__u64 sofar;		/* How many pkts we've sent so far */
2581da177e4SLinus Torvalds 	__u64 tx_bytes;		/* How many bytes we've transmitted */
259f466dba1SJohn Fastabend 	__u64 errors;		/* Errors when trying to transmit, */
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	/* runtime counters relating to clone_skb */
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	__u64 allocated_skbs;
2641da177e4SLinus Torvalds 	__u32 clone_count;
2651da177e4SLinus Torvalds 	int last_ok;		/* Was last skb sent?
26663adc6fbSStephen Hemminger 				 * Or a failed transmit of some sort?
26763adc6fbSStephen Hemminger 				 * This will keep sequence numbers in order
2681da177e4SLinus Torvalds 				 */
269fd29cf72SStephen Hemminger 	ktime_t next_tx;
270fd29cf72SStephen Hemminger 	ktime_t started_at;
271fd29cf72SStephen Hemminger 	ktime_t stopped_at;
272fd29cf72SStephen Hemminger 	u64	idle_acc;	/* nano-seconds */
273fd29cf72SStephen Hemminger 
2741da177e4SLinus Torvalds 	__u32 seq_num;
2751da177e4SLinus Torvalds 
27663adc6fbSStephen Hemminger 	int clone_skb;		/*
27763adc6fbSStephen Hemminger 				 * Use multiple SKBs during packet gen.
27863adc6fbSStephen Hemminger 				 * If this number is greater than 1, then
27963adc6fbSStephen Hemminger 				 * that many copies of the same packet will be
28063adc6fbSStephen Hemminger 				 * sent before a new packet is allocated.
28163adc6fbSStephen Hemminger 				 * If you want to send 1024 identical packets
28263adc6fbSStephen Hemminger 				 * before creating a new packet,
28363adc6fbSStephen Hemminger 				 * set clone_skb to 1024.
2841da177e4SLinus Torvalds 				 */
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	char dst_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
2871da177e4SLinus Torvalds 	char dst_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
2881da177e4SLinus Torvalds 	char src_min[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
2891da177e4SLinus Torvalds 	char src_max[IP_NAME_SZ];	/* IP, ie 1.2.3.4 */
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	struct in6_addr in6_saddr;
2921da177e4SLinus Torvalds 	struct in6_addr in6_daddr;
2931da177e4SLinus Torvalds 	struct in6_addr cur_in6_daddr;
2941da177e4SLinus Torvalds 	struct in6_addr cur_in6_saddr;
2951da177e4SLinus Torvalds 	/* For ranges */
2961da177e4SLinus Torvalds 	struct in6_addr min_in6_daddr;
2971da177e4SLinus Torvalds 	struct in6_addr max_in6_daddr;
2981da177e4SLinus Torvalds 	struct in6_addr min_in6_saddr;
2991da177e4SLinus Torvalds 	struct in6_addr max_in6_saddr;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	/* If we're doing ranges, random or incremental, then this
3021da177e4SLinus Torvalds 	 * defines the min/max for those ranges.
3031da177e4SLinus Torvalds 	 */
304252e3346SAl Viro 	__be32 saddr_min;	/* inclusive, source IP address */
305252e3346SAl Viro 	__be32 saddr_max;	/* exclusive, source IP address */
306252e3346SAl Viro 	__be32 daddr_min;	/* inclusive, dest IP address */
307252e3346SAl Viro 	__be32 daddr_max;	/* exclusive, dest IP address */
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	__u16 udp_src_min;	/* inclusive, source UDP port */
3101da177e4SLinus Torvalds 	__u16 udp_src_max;	/* exclusive, source UDP port */
3111da177e4SLinus Torvalds 	__u16 udp_dst_min;	/* inclusive, dest UDP port */
3121da177e4SLinus Torvalds 	__u16 udp_dst_max;	/* exclusive, dest UDP port */
3131da177e4SLinus Torvalds 
3141ca7768cSFrancesco Fondelli 	/* DSCP + ECN */
31563adc6fbSStephen Hemminger 	__u8 tos;            /* six MSB of (former) IPv4 TOS
31663adc6fbSStephen Hemminger 				are for dscp codepoint */
31763adc6fbSStephen Hemminger 	__u8 traffic_class;  /* ditto for the (former) Traffic Class in IPv6
31863adc6fbSStephen Hemminger 				(see RFC 3260, sec. 4) */
3191ca7768cSFrancesco Fondelli 
320ca6549afSSteven Whitehouse 	/* MPLS */
321ca6549afSSteven Whitehouse 	unsigned nr_labels;	/* Depth of stack, 0 = no MPLS */
322ca6549afSSteven Whitehouse 	__be32 labels[MAX_MPLS_LABELS];
323ca6549afSSteven Whitehouse 
32434954ddcSFrancesco Fondelli 	/* VLAN/SVLAN (802.1Q/Q-in-Q) */
32534954ddcSFrancesco Fondelli 	__u8  vlan_p;
32634954ddcSFrancesco Fondelli 	__u8  vlan_cfi;
32734954ddcSFrancesco Fondelli 	__u16 vlan_id;  /* 0xffff means no vlan tag */
32834954ddcSFrancesco Fondelli 
32934954ddcSFrancesco Fondelli 	__u8  svlan_p;
33034954ddcSFrancesco Fondelli 	__u8  svlan_cfi;
33134954ddcSFrancesco Fondelli 	__u16 svlan_id; /* 0xffff means no svlan tag */
33234954ddcSFrancesco Fondelli 
3331da177e4SLinus Torvalds 	__u32 src_mac_count;	/* How many MACs to iterate through */
3341da177e4SLinus Torvalds 	__u32 dst_mac_count;	/* How many MACs to iterate through */
3351da177e4SLinus Torvalds 
336f404e9a6SKris Katterjohn 	unsigned char dst_mac[ETH_ALEN];
337f404e9a6SKris Katterjohn 	unsigned char src_mac[ETH_ALEN];
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	__u32 cur_dst_mac_offset;
3401da177e4SLinus Torvalds 	__u32 cur_src_mac_offset;
341252e3346SAl Viro 	__be32 cur_saddr;
342252e3346SAl Viro 	__be32 cur_daddr;
34366ed1e5eSEric Dumazet 	__u16 ip_id;
3441da177e4SLinus Torvalds 	__u16 cur_udp_dst;
3451da177e4SLinus Torvalds 	__u16 cur_udp_src;
34645b270f8SRobert Olsson 	__u16 cur_queue_map;
3471da177e4SLinus Torvalds 	__u32 cur_pkt_size;
348baac8564SEric Dumazet 	__u32 last_pkt_size;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	__u8 hh[14];
3511da177e4SLinus Torvalds 	/* = {
3521da177e4SLinus Torvalds 	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB,
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	   We fill in SRC address later
3551da177e4SLinus Torvalds 	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3561da177e4SLinus Torvalds 	   0x08, 0x00
3571da177e4SLinus Torvalds 	   };
3581da177e4SLinus Torvalds 	 */
3591da177e4SLinus Torvalds 	__u16 pad;		/* pad out the hh struct to an even 16 bytes */
3601da177e4SLinus Torvalds 
36163adc6fbSStephen Hemminger 	struct sk_buff *skb;	/* skb we are to transmit next, used for when we
3621da177e4SLinus Torvalds 				 * are transmitting the same one multiple times
3631da177e4SLinus Torvalds 				 */
36463adc6fbSStephen Hemminger 	struct net_device *odev; /* The out-going device.
36563adc6fbSStephen Hemminger 				  * Note that the device should have it's
36663adc6fbSStephen Hemminger 				  * pg_info pointer pointing back to this
36763adc6fbSStephen Hemminger 				  * device.
36863adc6fbSStephen Hemminger 				  * Set when the user specifies the out-going
36963adc6fbSStephen Hemminger 				  * device name (not when the inject is
3701da177e4SLinus Torvalds 				  * started as it used to do.)
3711da177e4SLinus Torvalds 				  */
372593f63b0SEric Dumazet 	char odevname[32];
3731da177e4SLinus Torvalds 	struct flow_state *flows;
3741da177e4SLinus Torvalds 	unsigned cflows;	/* Concurrent flows (config) */
3751da177e4SLinus Torvalds 	unsigned lflow;		/* Flow length  (config) */
3761da177e4SLinus Torvalds 	unsigned nflows;	/* accumulated flows (stats) */
377007a531bSJamal Hadi Salim 	unsigned curfl;		/* current sequenced flow (state)*/
37845b270f8SRobert Olsson 
37945b270f8SRobert Olsson 	u16 queue_map_min;
38045b270f8SRobert Olsson 	u16 queue_map_max;
381e99b99b4SRobert Olsson 	int node;               /* Memory node */
38245b270f8SRobert Olsson 
383a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
384a553e4a6SJamal Hadi Salim 	__u8	ipsmode;		/* IPSEC mode (config) */
385a553e4a6SJamal Hadi Salim 	__u8	ipsproto;		/* IPSEC type (config) */
386a553e4a6SJamal Hadi Salim #endif
38739df232fSStephen Hemminger 	char result[512];
3881da177e4SLinus Torvalds };
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds struct pktgen_hdr {
391252e3346SAl Viro 	__be32 pgh_magic;
392252e3346SAl Viro 	__be32 seq_num;
393252e3346SAl Viro 	__be32 tv_sec;
394252e3346SAl Viro 	__be32 tv_usec;
3951da177e4SLinus Torvalds };
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds struct pktgen_thread {
39863adc6fbSStephen Hemminger 	spinlock_t if_lock;		/* for list of devices */
399c26a8016SLuiz Capitulino 	struct list_head if_list;	/* All device here */
400cdcdbe0bSLuiz Capitulino 	struct list_head th_list;
401ee74baa7SDavid S. Miller 	struct task_struct *tsk;
4021da177e4SLinus Torvalds 	char result[512];
4031da177e4SLinus Torvalds 
40463adc6fbSStephen Hemminger 	/* Field for thread to receive "posted" events terminate,
40563adc6fbSStephen Hemminger 	   stop ifs etc. */
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	u32 control;
4081da177e4SLinus Torvalds 	int cpu;
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	wait_queue_head_t queue;
411d3ede327SDenis V. Lunev 	struct completion start_done;
4121da177e4SLinus Torvalds };
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds #define REMOVE 1
4151da177e4SLinus Torvalds #define FIND   0
4161da177e4SLinus Torvalds 
417fd29cf72SStephen Hemminger static inline ktime_t ktime_now(void)
4181da177e4SLinus Torvalds {
419fd29cf72SStephen Hemminger 	struct timespec ts;
420fd29cf72SStephen Hemminger 	ktime_get_ts(&ts);
421fd29cf72SStephen Hemminger 
422fd29cf72SStephen Hemminger 	return timespec_to_ktime(ts);
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds 
425fd29cf72SStephen Hemminger /* This works even if 32 bit because of careful byte order choice */
426fd29cf72SStephen Hemminger static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
4271da177e4SLinus Torvalds {
428fd29cf72SStephen Hemminger 	return cmp1.tv64 < cmp2.tv64;
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds 
431c3d2f52dSStephen Hemminger static const char version[] =
432f9467eaeSJoe Perches 	"Packet Generator for packet performance testing. "
433f9467eaeSJoe Perches 	"Version: " VERSION "\n";
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
4361da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname);
437222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
4383e984840SEric Dumazet 					  const char *ifname, bool exact);
4391da177e4SLinus Torvalds static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
4401da177e4SLinus Torvalds static void pktgen_run_all_threads(void);
441eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void);
4421da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void);
4433bda06a3SStephen Hemminger 
4441da177e4SLinus Torvalds static void pktgen_stop(struct pktgen_thread *t);
4451da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
44639df232fSStephen Hemminger 
4471da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16]);
4481da177e4SLinus Torvalds static unsigned int fmt_ip6(char *s, const char ip[16]);
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds /* Module parameters, defaults. */
45165c5b786SStephen Hemminger static int pg_count_d __read_mostly = 1000;
45265c5b786SStephen Hemminger static int pg_delay_d __read_mostly;
45365c5b786SStephen Hemminger static int pg_clone_skb_d  __read_mostly;
45465c5b786SStephen Hemminger static int debug  __read_mostly;
4551da177e4SLinus Torvalds 
456222fa076SLuiz Capitulino static DEFINE_MUTEX(pktgen_thread_lock);
457cdcdbe0bSLuiz Capitulino static LIST_HEAD(pktgen_threads);
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds static struct notifier_block pktgen_notifier_block = {
4601da177e4SLinus Torvalds 	.notifier_call = pktgen_device_event,
4611da177e4SLinus Torvalds };
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds /*
4641da177e4SLinus Torvalds  * /proc handling functions
4651da177e4SLinus Torvalds  *
4661da177e4SLinus Torvalds  */
4671da177e4SLinus Torvalds 
468d50a6b56SStephen Hemminger static int pgctrl_show(struct seq_file *seq, void *v)
469d50a6b56SStephen Hemminger {
470c3d2f52dSStephen Hemminger 	seq_puts(seq, version);
471d50a6b56SStephen Hemminger 	return 0;
472d50a6b56SStephen Hemminger }
4731da177e4SLinus Torvalds 
474d50a6b56SStephen Hemminger static ssize_t pgctrl_write(struct file *file, const char __user *buf,
4751da177e4SLinus Torvalds 			    size_t count, loff_t *ppos)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds 	int err = 0;
478d50a6b56SStephen Hemminger 	char data[128];
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds 	if (!capable(CAP_NET_ADMIN)) {
4811da177e4SLinus Torvalds 		err = -EPERM;
4821da177e4SLinus Torvalds 		goto out;
4831da177e4SLinus Torvalds 	}
4841da177e4SLinus Torvalds 
485d50a6b56SStephen Hemminger 	if (count > sizeof(data))
486d50a6b56SStephen Hemminger 		count = sizeof(data);
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds 	if (copy_from_user(data, buf, count)) {
4891da177e4SLinus Torvalds 		err = -EFAULT;
490d50a6b56SStephen Hemminger 		goto out;
4911da177e4SLinus Torvalds 	}
4921da177e4SLinus Torvalds 	data[count - 1] = 0;	/* Make string */
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds 	if (!strcmp(data, "stop"))
4951da177e4SLinus Torvalds 		pktgen_stop_all_threads_ifs();
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 	else if (!strcmp(data, "start"))
4981da177e4SLinus Torvalds 		pktgen_run_all_threads();
4991da177e4SLinus Torvalds 
500eb37b41cSJesse Brandeburg 	else if (!strcmp(data, "reset"))
501eb37b41cSJesse Brandeburg 		pktgen_reset_all_threads();
502eb37b41cSJesse Brandeburg 
5031da177e4SLinus Torvalds 	else
504f9467eaeSJoe Perches 		pr_warning("Unknown command: %s\n", data);
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	err = count;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds out:
5091da177e4SLinus Torvalds 	return err;
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds 
512d50a6b56SStephen Hemminger static int pgctrl_open(struct inode *inode, struct file *file)
5131da177e4SLinus Torvalds {
514d50a6b56SStephen Hemminger 	return single_open(file, pgctrl_show, PDE(inode)->data);
515d50a6b56SStephen Hemminger }
516d50a6b56SStephen Hemminger 
5179a32144eSArjan van de Ven static const struct file_operations pktgen_fops = {
518d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
519d50a6b56SStephen Hemminger 	.open    = pgctrl_open,
520d50a6b56SStephen Hemminger 	.read    = seq_read,
521d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
522d50a6b56SStephen Hemminger 	.write   = pgctrl_write,
523d50a6b56SStephen Hemminger 	.release = single_release,
524d50a6b56SStephen Hemminger };
525d50a6b56SStephen Hemminger 
526d50a6b56SStephen Hemminger static int pktgen_if_show(struct seq_file *seq, void *v)
527d50a6b56SStephen Hemminger {
528648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev = seq->private;
529fd29cf72SStephen Hemminger 	ktime_t stopped;
530fd29cf72SStephen Hemminger 	u64 idle;
5311da177e4SLinus Torvalds 
532222f1806SLuiz Capitulino 	seq_printf(seq,
533222f1806SLuiz Capitulino 		   "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
534222f1806SLuiz Capitulino 		   (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
535222f1806SLuiz Capitulino 		   pkt_dev->max_pkt_size);
5361da177e4SLinus Torvalds 
537222f1806SLuiz Capitulino 	seq_printf(seq,
538fd29cf72SStephen Hemminger 		   "     frags: %d  delay: %llu  clone_skb: %d  ifname: %s\n",
539fd29cf72SStephen Hemminger 		   pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
540593f63b0SEric Dumazet 		   pkt_dev->clone_skb, pkt_dev->odevname);
5411da177e4SLinus Torvalds 
542222f1806SLuiz Capitulino 	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
543222f1806SLuiz Capitulino 		   pkt_dev->lflow);
5441da177e4SLinus Torvalds 
54545b270f8SRobert Olsson 	seq_printf(seq,
54645b270f8SRobert Olsson 		   "     queue_map_min: %u  queue_map_max: %u\n",
54745b270f8SRobert Olsson 		   pkt_dev->queue_map_min,
54845b270f8SRobert Olsson 		   pkt_dev->queue_map_max);
54945b270f8SRobert Olsson 
5501da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
5511da177e4SLinus Torvalds 		char b1[128], b2[128], b3[128];
5521da177e4SLinus Torvalds 		fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
5531da177e4SLinus Torvalds 		fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr);
5541da177e4SLinus Torvalds 		fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr);
555222f1806SLuiz Capitulino 		seq_printf(seq,
556222f1806SLuiz Capitulino 			   "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1,
557222f1806SLuiz Capitulino 			   b2, b3);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 		fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr);
5601da177e4SLinus Torvalds 		fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr);
5611da177e4SLinus Torvalds 		fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr);
562222f1806SLuiz Capitulino 		seq_printf(seq,
563222f1806SLuiz Capitulino 			   "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1,
564222f1806SLuiz Capitulino 			   b2, b3);
5651da177e4SLinus Torvalds 
56663adc6fbSStephen Hemminger 	} else {
567222f1806SLuiz Capitulino 		seq_printf(seq,
56863adc6fbSStephen Hemminger 			   "     dst_min: %s  dst_max: %s\n",
56963adc6fbSStephen Hemminger 			   pkt_dev->dst_min, pkt_dev->dst_max);
57063adc6fbSStephen Hemminger 		seq_printf(seq,
57163adc6fbSStephen Hemminger 			   "        src_min: %s  src_max: %s\n",
57263adc6fbSStephen Hemminger 			   pkt_dev->src_min, pkt_dev->src_max);
57363adc6fbSStephen Hemminger 	}
5741da177e4SLinus Torvalds 
575d50a6b56SStephen Hemminger 	seq_puts(seq, "     src_mac: ");
5761da177e4SLinus Torvalds 
577e174961cSJohannes Berg 	seq_printf(seq, "%pM ",
578e174961cSJohannes Berg 		   is_zero_ether_addr(pkt_dev->src_mac) ?
579e174961cSJohannes Berg 			     pkt_dev->odev->dev_addr : pkt_dev->src_mac);
5801da177e4SLinus Torvalds 
581d50a6b56SStephen Hemminger 	seq_printf(seq, "dst_mac: ");
582e174961cSJohannes Berg 	seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
5831da177e4SLinus Torvalds 
584222f1806SLuiz Capitulino 	seq_printf(seq,
58563adc6fbSStephen Hemminger 		   "     udp_src_min: %d  udp_src_max: %d"
58663adc6fbSStephen Hemminger 		   "  udp_dst_min: %d  udp_dst_max: %d\n",
587222f1806SLuiz Capitulino 		   pkt_dev->udp_src_min, pkt_dev->udp_src_max,
588222f1806SLuiz Capitulino 		   pkt_dev->udp_dst_min, pkt_dev->udp_dst_max);
5891da177e4SLinus Torvalds 
590222f1806SLuiz Capitulino 	seq_printf(seq,
591ca6549afSSteven Whitehouse 		   "     src_mac_count: %d  dst_mac_count: %d\n",
5921da177e4SLinus Torvalds 		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);
5931da177e4SLinus Torvalds 
594ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels) {
595ca6549afSSteven Whitehouse 		unsigned i;
596ca6549afSSteven Whitehouse 		seq_printf(seq, "     mpls: ");
597ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
598ca6549afSSteven Whitehouse 			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
599ca6549afSSteven Whitehouse 				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
600ca6549afSSteven Whitehouse 	}
601ca6549afSSteven Whitehouse 
60263adc6fbSStephen Hemminger 	if (pkt_dev->vlan_id != 0xffff)
60334954ddcSFrancesco Fondelli 		seq_printf(seq, "     vlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
60463adc6fbSStephen Hemminger 			   pkt_dev->vlan_id, pkt_dev->vlan_p,
60563adc6fbSStephen Hemminger 			   pkt_dev->vlan_cfi);
60634954ddcSFrancesco Fondelli 
60763adc6fbSStephen Hemminger 	if (pkt_dev->svlan_id != 0xffff)
60834954ddcSFrancesco Fondelli 		seq_printf(seq, "     svlan_id: %u  vlan_p: %u  vlan_cfi: %u\n",
60963adc6fbSStephen Hemminger 			   pkt_dev->svlan_id, pkt_dev->svlan_p,
61063adc6fbSStephen Hemminger 			   pkt_dev->svlan_cfi);
61134954ddcSFrancesco Fondelli 
61263adc6fbSStephen Hemminger 	if (pkt_dev->tos)
6131ca7768cSFrancesco Fondelli 		seq_printf(seq, "     tos: 0x%02x\n", pkt_dev->tos);
6141ca7768cSFrancesco Fondelli 
61563adc6fbSStephen Hemminger 	if (pkt_dev->traffic_class)
6161ca7768cSFrancesco Fondelli 		seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
6171ca7768cSFrancesco Fondelli 
618e99b99b4SRobert Olsson 	if (pkt_dev->node >= 0)
619e99b99b4SRobert Olsson 		seq_printf(seq, "     node: %d\n", pkt_dev->node);
620e99b99b4SRobert Olsson 
621ca6549afSSteven Whitehouse 	seq_printf(seq, "     Flags: ");
622ca6549afSSteven Whitehouse 
6231da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
624d50a6b56SStephen Hemminger 		seq_printf(seq, "IPV6  ");
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPSRC_RND)
627d50a6b56SStephen Hemminger 		seq_printf(seq, "IPSRC_RND  ");
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPDST_RND)
630d50a6b56SStephen Hemminger 		seq_printf(seq, "IPDST_RND  ");
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	if (pkt_dev->flags & F_TXSIZE_RND)
633d50a6b56SStephen Hemminger 		seq_printf(seq, "TXSIZE_RND  ");
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPSRC_RND)
636d50a6b56SStephen Hemminger 		seq_printf(seq, "UDPSRC_RND  ");
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	if (pkt_dev->flags & F_UDPDST_RND)
639d50a6b56SStephen Hemminger 		seq_printf(seq, "UDPDST_RND  ");
6401da177e4SLinus Torvalds 
641ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND)
642ca6549afSSteven Whitehouse 		seq_printf(seq,  "MPLS_RND  ");
643ca6549afSSteven Whitehouse 
64445b270f8SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_RND)
64545b270f8SRobert Olsson 		seq_printf(seq,  "QUEUE_MAP_RND  ");
64645b270f8SRobert Olsson 
647e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
648e6fce5b9SRobert Olsson 		seq_printf(seq,  "QUEUE_MAP_CPU  ");
649e6fce5b9SRobert Olsson 
650007a531bSJamal Hadi Salim 	if (pkt_dev->cflows) {
651007a531bSJamal Hadi Salim 		if (pkt_dev->flags & F_FLOW_SEQ)
652007a531bSJamal Hadi Salim 			seq_printf(seq,  "FLOW_SEQ  "); /*in sequence flows*/
653007a531bSJamal Hadi Salim 		else
654007a531bSJamal Hadi Salim 			seq_printf(seq,  "FLOW_RND  ");
655007a531bSJamal Hadi Salim 	}
656007a531bSJamal Hadi Salim 
657a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
658a553e4a6SJamal Hadi Salim 	if (pkt_dev->flags & F_IPSEC_ON)
659a553e4a6SJamal Hadi Salim 		seq_printf(seq,  "IPSEC  ");
660a553e4a6SJamal Hadi Salim #endif
661a553e4a6SJamal Hadi Salim 
6621da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACSRC_RND)
663d50a6b56SStephen Hemminger 		seq_printf(seq, "MACSRC_RND  ");
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 	if (pkt_dev->flags & F_MACDST_RND)
666d50a6b56SStephen Hemminger 		seq_printf(seq, "MACDST_RND  ");
6671da177e4SLinus Torvalds 
66834954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_VID_RND)
66934954ddcSFrancesco Fondelli 		seq_printf(seq, "VID_RND  ");
67034954ddcSFrancesco Fondelli 
67134954ddcSFrancesco Fondelli 	if (pkt_dev->flags & F_SVID_RND)
67234954ddcSFrancesco Fondelli 		seq_printf(seq, "SVID_RND  ");
67334954ddcSFrancesco Fondelli 
674e99b99b4SRobert Olsson 	if (pkt_dev->flags & F_NODE)
675e99b99b4SRobert Olsson 		seq_printf(seq, "NODE_ALLOC  ");
676e99b99b4SRobert Olsson 
677d50a6b56SStephen Hemminger 	seq_puts(seq, "\n");
6781da177e4SLinus Torvalds 
679fd29cf72SStephen Hemminger 	/* not really stopped, more like last-running-at */
680fd29cf72SStephen Hemminger 	stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at;
681fd29cf72SStephen Hemminger 	idle = pkt_dev->idle_acc;
682fd29cf72SStephen Hemminger 	do_div(idle, NSEC_PER_USEC);
6831da177e4SLinus Torvalds 
684222f1806SLuiz Capitulino 	seq_printf(seq,
685fd29cf72SStephen Hemminger 		   "Current:\n     pkts-sofar: %llu  errors: %llu\n",
6861da177e4SLinus Torvalds 		   (unsigned long long)pkt_dev->sofar,
687fd29cf72SStephen Hemminger 		   (unsigned long long)pkt_dev->errors);
688fd29cf72SStephen Hemminger 
689fd29cf72SStephen Hemminger 	seq_printf(seq,
690fd29cf72SStephen Hemminger 		   "     started: %lluus  stopped: %lluus idle: %lluus\n",
691fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(pkt_dev->started_at),
692fd29cf72SStephen Hemminger 		   (unsigned long long) ktime_to_us(stopped),
693fd29cf72SStephen Hemminger 		   (unsigned long long) idle);
6941da177e4SLinus Torvalds 
695222f1806SLuiz Capitulino 	seq_printf(seq,
696222f1806SLuiz Capitulino 		   "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
697d50a6b56SStephen Hemminger 		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
698d50a6b56SStephen Hemminger 		   pkt_dev->cur_src_mac_offset);
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
7011da177e4SLinus Torvalds 		char b1[128], b2[128];
7021da177e4SLinus Torvalds 		fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr);
7031da177e4SLinus Torvalds 		fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr);
704d50a6b56SStephen Hemminger 		seq_printf(seq, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
705222f1806SLuiz Capitulino 	} else
706d50a6b56SStephen Hemminger 		seq_printf(seq, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
7071da177e4SLinus Torvalds 			   pkt_dev->cur_saddr, pkt_dev->cur_daddr);
7081da177e4SLinus Torvalds 
709d50a6b56SStephen Hemminger 	seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
7101da177e4SLinus Torvalds 		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
7111da177e4SLinus Torvalds 
71245b270f8SRobert Olsson 	seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);
71345b270f8SRobert Olsson 
714d50a6b56SStephen Hemminger 	seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	if (pkt_dev->result[0])
717d50a6b56SStephen Hemminger 		seq_printf(seq, "Result: %s\n", pkt_dev->result);
7181da177e4SLinus Torvalds 	else
719d50a6b56SStephen Hemminger 		seq_printf(seq, "Result: Idle\n");
7201da177e4SLinus Torvalds 
721d50a6b56SStephen Hemminger 	return 0;
7221da177e4SLinus Torvalds }
7231da177e4SLinus Torvalds 
724ca6549afSSteven Whitehouse 
72563adc6fbSStephen Hemminger static int hex32_arg(const char __user *user_buffer, unsigned long maxlen,
72663adc6fbSStephen Hemminger 		     __u32 *num)
727ca6549afSSteven Whitehouse {
728ca6549afSSteven Whitehouse 	int i = 0;
729ca6549afSSteven Whitehouse 	*num = 0;
730ca6549afSSteven Whitehouse 
7311ca7768cSFrancesco Fondelli 	for (; i < maxlen; i++) {
73282fd5b5dSAndy Shevchenko 		int value;
733ca6549afSSteven Whitehouse 		char c;
734ca6549afSSteven Whitehouse 		*num <<= 4;
735ca6549afSSteven Whitehouse 		if (get_user(c, &user_buffer[i]))
736ca6549afSSteven Whitehouse 			return -EFAULT;
73782fd5b5dSAndy Shevchenko 		value = hex_to_bin(c);
73882fd5b5dSAndy Shevchenko 		if (value >= 0)
73982fd5b5dSAndy Shevchenko 			*num |= value;
740ca6549afSSteven Whitehouse 		else
741ca6549afSSteven Whitehouse 			break;
742ca6549afSSteven Whitehouse 	}
743ca6549afSSteven Whitehouse 	return i;
744ca6549afSSteven Whitehouse }
745ca6549afSSteven Whitehouse 
746222f1806SLuiz Capitulino static int count_trail_chars(const char __user * user_buffer,
747222f1806SLuiz Capitulino 			     unsigned int maxlen)
7481da177e4SLinus Torvalds {
7491da177e4SLinus Torvalds 	int i;
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds 	for (i = 0; i < maxlen; i++) {
7521da177e4SLinus Torvalds 		char c;
7531da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7541da177e4SLinus Torvalds 			return -EFAULT;
7551da177e4SLinus Torvalds 		switch (c) {
7561da177e4SLinus Torvalds 		case '\"':
7571da177e4SLinus Torvalds 		case '\n':
7581da177e4SLinus Torvalds 		case '\r':
7591da177e4SLinus Torvalds 		case '\t':
7601da177e4SLinus Torvalds 		case ' ':
7611da177e4SLinus Torvalds 		case '=':
7621da177e4SLinus Torvalds 			break;
7631da177e4SLinus Torvalds 		default:
7641da177e4SLinus Torvalds 			goto done;
7653ff50b79SStephen Hemminger 		}
7661da177e4SLinus Torvalds 	}
7671da177e4SLinus Torvalds done:
7681da177e4SLinus Torvalds 	return i;
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds 
771222f1806SLuiz Capitulino static unsigned long num_arg(const char __user * user_buffer,
772222f1806SLuiz Capitulino 			     unsigned long maxlen, unsigned long *num)
7731da177e4SLinus Torvalds {
774d6182223SPaul Gortmaker 	int i;
7751da177e4SLinus Torvalds 	*num = 0;
7761da177e4SLinus Torvalds 
777d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
7781da177e4SLinus Torvalds 		char c;
7791da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7801da177e4SLinus Torvalds 			return -EFAULT;
7811da177e4SLinus Torvalds 		if ((c >= '0') && (c <= '9')) {
7821da177e4SLinus Torvalds 			*num *= 10;
7831da177e4SLinus Torvalds 			*num += c - '0';
7841da177e4SLinus Torvalds 		} else
7851da177e4SLinus Torvalds 			break;
7861da177e4SLinus Torvalds 	}
7871da177e4SLinus Torvalds 	return i;
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds static int strn_len(const char __user * user_buffer, unsigned int maxlen)
7911da177e4SLinus Torvalds {
792d6182223SPaul Gortmaker 	int i;
7931da177e4SLinus Torvalds 
794d6182223SPaul Gortmaker 	for (i = 0; i < maxlen; i++) {
7951da177e4SLinus Torvalds 		char c;
7961da177e4SLinus Torvalds 		if (get_user(c, &user_buffer[i]))
7971da177e4SLinus Torvalds 			return -EFAULT;
7981da177e4SLinus Torvalds 		switch (c) {
7991da177e4SLinus Torvalds 		case '\"':
8001da177e4SLinus Torvalds 		case '\n':
8011da177e4SLinus Torvalds 		case '\r':
8021da177e4SLinus Torvalds 		case '\t':
8031da177e4SLinus Torvalds 		case ' ':
8041da177e4SLinus Torvalds 			goto done_str;
8051da177e4SLinus Torvalds 			break;
8061da177e4SLinus Torvalds 		default:
8071da177e4SLinus Torvalds 			break;
8083ff50b79SStephen Hemminger 		}
8091da177e4SLinus Torvalds 	}
8101da177e4SLinus Torvalds done_str:
8111da177e4SLinus Torvalds 	return i;
8121da177e4SLinus Torvalds }
8131da177e4SLinus Torvalds 
814ca6549afSSteven Whitehouse static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
815ca6549afSSteven Whitehouse {
816ca6549afSSteven Whitehouse 	unsigned n = 0;
817ca6549afSSteven Whitehouse 	char c;
818ca6549afSSteven Whitehouse 	ssize_t i = 0;
819ca6549afSSteven Whitehouse 	int len;
820ca6549afSSteven Whitehouse 
821ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = 0;
822ca6549afSSteven Whitehouse 	do {
823ca6549afSSteven Whitehouse 		__u32 tmp;
8241ca7768cSFrancesco Fondelli 		len = hex32_arg(&buffer[i], 8, &tmp);
825ca6549afSSteven Whitehouse 		if (len <= 0)
826ca6549afSSteven Whitehouse 			return len;
827ca6549afSSteven Whitehouse 		pkt_dev->labels[n] = htonl(tmp);
828ca6549afSSteven Whitehouse 		if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM)
829ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
830ca6549afSSteven Whitehouse 		i += len;
831ca6549afSSteven Whitehouse 		if (get_user(c, &buffer[i]))
832ca6549afSSteven Whitehouse 			return -EFAULT;
833ca6549afSSteven Whitehouse 		i++;
834ca6549afSSteven Whitehouse 		n++;
835ca6549afSSteven Whitehouse 		if (n >= MAX_MPLS_LABELS)
836ca6549afSSteven Whitehouse 			return -E2BIG;
837ca6549afSSteven Whitehouse 	} while (c == ',');
838ca6549afSSteven Whitehouse 
839ca6549afSSteven Whitehouse 	pkt_dev->nr_labels = n;
840ca6549afSSteven Whitehouse 	return i;
841ca6549afSSteven Whitehouse }
842ca6549afSSteven Whitehouse 
843222f1806SLuiz Capitulino static ssize_t pktgen_if_write(struct file *file,
844222f1806SLuiz Capitulino 			       const char __user * user_buffer, size_t count,
845222f1806SLuiz Capitulino 			       loff_t * offset)
8461da177e4SLinus Torvalds {
8478a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
848d50a6b56SStephen Hemminger 	struct pktgen_dev *pkt_dev = seq->private;
849d6182223SPaul Gortmaker 	int i, max, len;
8501da177e4SLinus Torvalds 	char name[16], valstr[32];
8511da177e4SLinus Torvalds 	unsigned long value = 0;
8521da177e4SLinus Torvalds 	char *pg_result = NULL;
8531da177e4SLinus Torvalds 	int tmp = 0;
8541da177e4SLinus Torvalds 	char buf[128];
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 	pg_result = &(pkt_dev->result[0]);
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 	if (count < 1) {
859f9467eaeSJoe Perches 		pr_warning("wrong command format\n");
8601da177e4SLinus Torvalds 		return -EINVAL;
8611da177e4SLinus Torvalds 	}
8621da177e4SLinus Torvalds 
863d6182223SPaul Gortmaker 	max = count;
864d6182223SPaul Gortmaker 	tmp = count_trail_chars(user_buffer, max);
8651da177e4SLinus Torvalds 	if (tmp < 0) {
866f9467eaeSJoe Perches 		pr_warning("illegal format\n");
8671da177e4SLinus Torvalds 		return tmp;
8681da177e4SLinus Torvalds 	}
869d6182223SPaul Gortmaker 	i = tmp;
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 	/* Read variable name */
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
87463adc6fbSStephen Hemminger 	if (len < 0)
875222f1806SLuiz Capitulino 		return len;
87663adc6fbSStephen Hemminger 
8771da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
8781da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
8791da177e4SLinus Torvalds 		return -EFAULT;
8801da177e4SLinus Torvalds 	i += len;
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	max = count - i;
8831da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
8841da177e4SLinus Torvalds 	if (len < 0)
8851da177e4SLinus Torvalds 		return len;
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	i += len;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	if (debug) {
890*448d7b5dSNelson Elhage 		size_t copy = min(count, 1023);
891*448d7b5dSNelson Elhage 		char tb[copy + 1];
892*448d7b5dSNelson Elhage 		if (copy_from_user(tb, user_buffer, copy))
8931da177e4SLinus Torvalds 			return -EFAULT;
894*448d7b5dSNelson Elhage 		tb[copy] = 0;
89525a8b254SDavid S. Miller 		printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,
896d50a6b56SStephen Hemminger 		       (unsigned long)count, tb);
8971da177e4SLinus Torvalds 	}
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	if (!strcmp(name, "min_pkt_size")) {
9001da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
90163adc6fbSStephen Hemminger 		if (len < 0)
902222f1806SLuiz Capitulino 			return len;
90363adc6fbSStephen Hemminger 
9041da177e4SLinus Torvalds 		i += len;
9051da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9061da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9071da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9081da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9091da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9101da177e4SLinus Torvalds 		}
911222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: min_pkt_size=%u",
912222f1806SLuiz Capitulino 			pkt_dev->min_pkt_size);
9131da177e4SLinus Torvalds 		return count;
9141da177e4SLinus Torvalds 	}
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 	if (!strcmp(name, "max_pkt_size")) {
9171da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
91863adc6fbSStephen Hemminger 		if (len < 0)
919222f1806SLuiz Capitulino 			return len;
92063adc6fbSStephen Hemminger 
9211da177e4SLinus Torvalds 		i += len;
9221da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9231da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9241da177e4SLinus Torvalds 		if (value != pkt_dev->max_pkt_size) {
9251da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9261da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9271da177e4SLinus Torvalds 		}
928222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: max_pkt_size=%u",
929222f1806SLuiz Capitulino 			pkt_dev->max_pkt_size);
9301da177e4SLinus Torvalds 		return count;
9311da177e4SLinus Torvalds 	}
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	/* Shortcut for min = max */
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	if (!strcmp(name, "pkt_size")) {
9361da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
93763adc6fbSStephen Hemminger 		if (len < 0)
938222f1806SLuiz Capitulino 			return len;
93963adc6fbSStephen Hemminger 
9401da177e4SLinus Torvalds 		i += len;
9411da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9421da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9431da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9441da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9451da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9461da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9471da177e4SLinus Torvalds 		}
9481da177e4SLinus Torvalds 		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
9491da177e4SLinus Torvalds 		return count;
9501da177e4SLinus Torvalds 	}
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	if (!strcmp(name, "debug")) {
9531da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
95463adc6fbSStephen Hemminger 		if (len < 0)
955222f1806SLuiz Capitulino 			return len;
95663adc6fbSStephen Hemminger 
9571da177e4SLinus Torvalds 		i += len;
9581da177e4SLinus Torvalds 		debug = value;
9591da177e4SLinus Torvalds 		sprintf(pg_result, "OK: debug=%u", debug);
9601da177e4SLinus Torvalds 		return count;
9611da177e4SLinus Torvalds 	}
9621da177e4SLinus Torvalds 
9631da177e4SLinus Torvalds 	if (!strcmp(name, "frags")) {
9641da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
96563adc6fbSStephen Hemminger 		if (len < 0)
966222f1806SLuiz Capitulino 			return len;
96763adc6fbSStephen Hemminger 
9681da177e4SLinus Torvalds 		i += len;
9691da177e4SLinus Torvalds 		pkt_dev->nfrags = value;
9701da177e4SLinus Torvalds 		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
9711da177e4SLinus Torvalds 		return count;
9721da177e4SLinus Torvalds 	}
9731da177e4SLinus Torvalds 	if (!strcmp(name, "delay")) {
9741da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
97563adc6fbSStephen Hemminger 		if (len < 0)
976222f1806SLuiz Capitulino 			return len;
97763adc6fbSStephen Hemminger 
9781da177e4SLinus Torvalds 		i += len;
979fd29cf72SStephen Hemminger 		if (value == 0x7FFFFFFF)
980fd29cf72SStephen Hemminger 			pkt_dev->delay = ULLONG_MAX;
981fd29cf72SStephen Hemminger 		else
9829240d715SEric Dumazet 			pkt_dev->delay = (u64)value;
983fd29cf72SStephen Hemminger 
984fd29cf72SStephen Hemminger 		sprintf(pg_result, "OK: delay=%llu",
985fd29cf72SStephen Hemminger 			(unsigned long long) pkt_dev->delay);
9861da177e4SLinus Torvalds 		return count;
9871da177e4SLinus Torvalds 	}
98843d28b65SDaniel Turull 	if (!strcmp(name, "rate")) {
98943d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
99043d28b65SDaniel Turull 		if (len < 0)
99143d28b65SDaniel Turull 			return len;
99243d28b65SDaniel Turull 
99343d28b65SDaniel Turull 		i += len;
99443d28b65SDaniel Turull 		if (!value)
99543d28b65SDaniel Turull 			return len;
99643d28b65SDaniel Turull 		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
99743d28b65SDaniel Turull 		if (debug)
998f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
99943d28b65SDaniel Turull 
100043d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
100143d28b65SDaniel Turull 		return count;
100243d28b65SDaniel Turull 	}
100343d28b65SDaniel Turull 	if (!strcmp(name, "ratep")) {
100443d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
100543d28b65SDaniel Turull 		if (len < 0)
100643d28b65SDaniel Turull 			return len;
100743d28b65SDaniel Turull 
100843d28b65SDaniel Turull 		i += len;
100943d28b65SDaniel Turull 		if (!value)
101043d28b65SDaniel Turull 			return len;
101143d28b65SDaniel Turull 		pkt_dev->delay = NSEC_PER_SEC/value;
101243d28b65SDaniel Turull 		if (debug)
1013f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
101443d28b65SDaniel Turull 
101543d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
101643d28b65SDaniel Turull 		return count;
101743d28b65SDaniel Turull 	}
10181da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_min")) {
10191da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
102063adc6fbSStephen Hemminger 		if (len < 0)
1021222f1806SLuiz Capitulino 			return len;
102263adc6fbSStephen Hemminger 
10231da177e4SLinus Torvalds 		i += len;
10241da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_min) {
10251da177e4SLinus Torvalds 			pkt_dev->udp_src_min = value;
10261da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10271da177e4SLinus Torvalds 		}
10281da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
10291da177e4SLinus Torvalds 		return count;
10301da177e4SLinus Torvalds 	}
10311da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_min")) {
10321da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
103363adc6fbSStephen Hemminger 		if (len < 0)
1034222f1806SLuiz Capitulino 			return len;
103563adc6fbSStephen Hemminger 
10361da177e4SLinus Torvalds 		i += len;
10371da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_min) {
10381da177e4SLinus Torvalds 			pkt_dev->udp_dst_min = value;
10391da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10401da177e4SLinus Torvalds 		}
10411da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
10421da177e4SLinus Torvalds 		return count;
10431da177e4SLinus Torvalds 	}
10441da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_max")) {
10451da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
104663adc6fbSStephen Hemminger 		if (len < 0)
1047222f1806SLuiz Capitulino 			return len;
104863adc6fbSStephen Hemminger 
10491da177e4SLinus Torvalds 		i += len;
10501da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_max) {
10511da177e4SLinus Torvalds 			pkt_dev->udp_src_max = value;
10521da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10531da177e4SLinus Torvalds 		}
10541da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
10551da177e4SLinus Torvalds 		return count;
10561da177e4SLinus Torvalds 	}
10571da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_max")) {
10581da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
105963adc6fbSStephen Hemminger 		if (len < 0)
1060222f1806SLuiz Capitulino 			return len;
106163adc6fbSStephen Hemminger 
10621da177e4SLinus Torvalds 		i += len;
10631da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_max) {
10641da177e4SLinus Torvalds 			pkt_dev->udp_dst_max = value;
10651da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10661da177e4SLinus Torvalds 		}
10671da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
10681da177e4SLinus Torvalds 		return count;
10691da177e4SLinus Torvalds 	}
10701da177e4SLinus Torvalds 	if (!strcmp(name, "clone_skb")) {
10711da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
107263adc6fbSStephen Hemminger 		if (len < 0)
1073222f1806SLuiz Capitulino 			return len;
107463adc6fbSStephen Hemminger 
10751da177e4SLinus Torvalds 		i += len;
10761da177e4SLinus Torvalds 		pkt_dev->clone_skb = value;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
10791da177e4SLinus Torvalds 		return count;
10801da177e4SLinus Torvalds 	}
10811da177e4SLinus Torvalds 	if (!strcmp(name, "count")) {
10821da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
108363adc6fbSStephen Hemminger 		if (len < 0)
1084222f1806SLuiz Capitulino 			return len;
108563adc6fbSStephen Hemminger 
10861da177e4SLinus Torvalds 		i += len;
10871da177e4SLinus Torvalds 		pkt_dev->count = value;
10881da177e4SLinus Torvalds 		sprintf(pg_result, "OK: count=%llu",
10891da177e4SLinus Torvalds 			(unsigned long long)pkt_dev->count);
10901da177e4SLinus Torvalds 		return count;
10911da177e4SLinus Torvalds 	}
10921da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac_count")) {
10931da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
109463adc6fbSStephen Hemminger 		if (len < 0)
1095222f1806SLuiz Capitulino 			return len;
109663adc6fbSStephen Hemminger 
10971da177e4SLinus Torvalds 		i += len;
10981da177e4SLinus Torvalds 		if (pkt_dev->src_mac_count != value) {
10991da177e4SLinus Torvalds 			pkt_dev->src_mac_count = value;
11001da177e4SLinus Torvalds 			pkt_dev->cur_src_mac_offset = 0;
11011da177e4SLinus Torvalds 		}
1102222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: src_mac_count=%d",
1103222f1806SLuiz Capitulino 			pkt_dev->src_mac_count);
11041da177e4SLinus Torvalds 		return count;
11051da177e4SLinus Torvalds 	}
11061da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac_count")) {
11071da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
110863adc6fbSStephen Hemminger 		if (len < 0)
1109222f1806SLuiz Capitulino 			return len;
111063adc6fbSStephen Hemminger 
11111da177e4SLinus Torvalds 		i += len;
11121da177e4SLinus Torvalds 		if (pkt_dev->dst_mac_count != value) {
11131da177e4SLinus Torvalds 			pkt_dev->dst_mac_count = value;
11141da177e4SLinus Torvalds 			pkt_dev->cur_dst_mac_offset = 0;
11151da177e4SLinus Torvalds 		}
1116222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: dst_mac_count=%d",
1117222f1806SLuiz Capitulino 			pkt_dev->dst_mac_count);
11181da177e4SLinus Torvalds 		return count;
11191da177e4SLinus Torvalds 	}
1120e99b99b4SRobert Olsson 	if (!strcmp(name, "node")) {
1121e99b99b4SRobert Olsson 		len = num_arg(&user_buffer[i], 10, &value);
1122e99b99b4SRobert Olsson 		if (len < 0)
1123e99b99b4SRobert Olsson 			return len;
1124e99b99b4SRobert Olsson 
1125e99b99b4SRobert Olsson 		i += len;
1126e99b99b4SRobert Olsson 
1127e99b99b4SRobert Olsson 		if (node_possible(value)) {
1128e99b99b4SRobert Olsson 			pkt_dev->node = value;
1129e99b99b4SRobert Olsson 			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
1130e99b99b4SRobert Olsson 		}
1131e99b99b4SRobert Olsson 		else
1132e99b99b4SRobert Olsson 			sprintf(pg_result, "ERROR: node not possible");
1133e99b99b4SRobert Olsson 		return count;
1134e99b99b4SRobert Olsson 	}
11351da177e4SLinus Torvalds 	if (!strcmp(name, "flag")) {
11361da177e4SLinus Torvalds 		char f[32];
11371da177e4SLinus Torvalds 		memset(f, 0, 32);
11381da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
113963adc6fbSStephen Hemminger 		if (len < 0)
1140222f1806SLuiz Capitulino 			return len;
114163adc6fbSStephen Hemminger 
11421da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
11431da177e4SLinus Torvalds 			return -EFAULT;
11441da177e4SLinus Torvalds 		i += len;
11451da177e4SLinus Torvalds 		if (strcmp(f, "IPSRC_RND") == 0)
11461da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPSRC_RND;
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds 		else if (strcmp(f, "!IPSRC_RND") == 0)
11491da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPSRC_RND;
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 		else if (strcmp(f, "TXSIZE_RND") == 0)
11521da177e4SLinus Torvalds 			pkt_dev->flags |= F_TXSIZE_RND;
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds 		else if (strcmp(f, "!TXSIZE_RND") == 0)
11551da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_TXSIZE_RND;
11561da177e4SLinus Torvalds 
11571da177e4SLinus Torvalds 		else if (strcmp(f, "IPDST_RND") == 0)
11581da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPDST_RND;
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 		else if (strcmp(f, "!IPDST_RND") == 0)
11611da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPDST_RND;
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 		else if (strcmp(f, "UDPSRC_RND") == 0)
11641da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPSRC_RND;
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPSRC_RND") == 0)
11671da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPSRC_RND;
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 		else if (strcmp(f, "UDPDST_RND") == 0)
11701da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPDST_RND;
11711da177e4SLinus Torvalds 
11721da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPDST_RND") == 0)
11731da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPDST_RND;
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 		else if (strcmp(f, "MACSRC_RND") == 0)
11761da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACSRC_RND;
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 		else if (strcmp(f, "!MACSRC_RND") == 0)
11791da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACSRC_RND;
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds 		else if (strcmp(f, "MACDST_RND") == 0)
11821da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACDST_RND;
11831da177e4SLinus Torvalds 
11841da177e4SLinus Torvalds 		else if (strcmp(f, "!MACDST_RND") == 0)
11851da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACDST_RND;
11861da177e4SLinus Torvalds 
1187ca6549afSSteven Whitehouse 		else if (strcmp(f, "MPLS_RND") == 0)
1188ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
1189ca6549afSSteven Whitehouse 
1190ca6549afSSteven Whitehouse 		else if (strcmp(f, "!MPLS_RND") == 0)
1191ca6549afSSteven Whitehouse 			pkt_dev->flags &= ~F_MPLS_RND;
1192ca6549afSSteven Whitehouse 
119334954ddcSFrancesco Fondelli 		else if (strcmp(f, "VID_RND") == 0)
119434954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_VID_RND;
119534954ddcSFrancesco Fondelli 
119634954ddcSFrancesco Fondelli 		else if (strcmp(f, "!VID_RND") == 0)
119734954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_VID_RND;
119834954ddcSFrancesco Fondelli 
119934954ddcSFrancesco Fondelli 		else if (strcmp(f, "SVID_RND") == 0)
120034954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_SVID_RND;
120134954ddcSFrancesco Fondelli 
120234954ddcSFrancesco Fondelli 		else if (strcmp(f, "!SVID_RND") == 0)
120334954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_SVID_RND;
120434954ddcSFrancesco Fondelli 
1205007a531bSJamal Hadi Salim 		else if (strcmp(f, "FLOW_SEQ") == 0)
1206007a531bSJamal Hadi Salim 			pkt_dev->flags |= F_FLOW_SEQ;
1207007a531bSJamal Hadi Salim 
120845b270f8SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_RND") == 0)
120945b270f8SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_RND;
121045b270f8SRobert Olsson 
121145b270f8SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
121245b270f8SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_RND;
1213e6fce5b9SRobert Olsson 
1214e6fce5b9SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_CPU") == 0)
1215e6fce5b9SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_CPU;
1216e6fce5b9SRobert Olsson 
1217e6fce5b9SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_CPU") == 0)
1218e6fce5b9SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
1219a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
1220a553e4a6SJamal Hadi Salim 		else if (strcmp(f, "IPSEC") == 0)
1221a553e4a6SJamal Hadi Salim 			pkt_dev->flags |= F_IPSEC_ON;
1222a553e4a6SJamal Hadi Salim #endif
1223a553e4a6SJamal Hadi Salim 
12241ca7768cSFrancesco Fondelli 		else if (strcmp(f, "!IPV6") == 0)
12251ca7768cSFrancesco Fondelli 			pkt_dev->flags &= ~F_IPV6;
12261ca7768cSFrancesco Fondelli 
1227e99b99b4SRobert Olsson 		else if (strcmp(f, "NODE_ALLOC") == 0)
1228e99b99b4SRobert Olsson 			pkt_dev->flags |= F_NODE;
1229e99b99b4SRobert Olsson 
1230e99b99b4SRobert Olsson 		else if (strcmp(f, "!NODE_ALLOC") == 0)
1231e99b99b4SRobert Olsson 			pkt_dev->flags &= ~F_NODE;
1232e99b99b4SRobert Olsson 
12331da177e4SLinus Torvalds 		else {
1234222f1806SLuiz Capitulino 			sprintf(pg_result,
1235222f1806SLuiz Capitulino 				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
12361da177e4SLinus Torvalds 				f,
12371ca7768cSFrancesco Fondelli 				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
1238e99b99b4SRobert Olsson 				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n");
12391da177e4SLinus Torvalds 			return count;
12401da177e4SLinus Torvalds 		}
12411da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
12421da177e4SLinus Torvalds 		return count;
12431da177e4SLinus Torvalds 	}
12441da177e4SLinus Torvalds 	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
12451da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
124663adc6fbSStephen Hemminger 		if (len < 0)
1247222f1806SLuiz Capitulino 			return len;
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12501da177e4SLinus Torvalds 			return -EFAULT;
12511da177e4SLinus Torvalds 		buf[len] = 0;
12521da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_min) != 0) {
12531da177e4SLinus Torvalds 			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
12541da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_min, buf, len);
12551da177e4SLinus Torvalds 			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
12561da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_min;
12571da177e4SLinus Torvalds 		}
12581da177e4SLinus Torvalds 		if (debug)
125925a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
1260222f1806SLuiz Capitulino 			       pkt_dev->dst_min);
12611da177e4SLinus Torvalds 		i += len;
12621da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
12631da177e4SLinus Torvalds 		return count;
12641da177e4SLinus Torvalds 	}
12651da177e4SLinus Torvalds 	if (!strcmp(name, "dst_max")) {
12661da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
126763adc6fbSStephen Hemminger 		if (len < 0)
1268222f1806SLuiz Capitulino 			return len;
126963adc6fbSStephen Hemminger 
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12721da177e4SLinus Torvalds 			return -EFAULT;
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds 		buf[len] = 0;
12751da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_max) != 0) {
12761da177e4SLinus Torvalds 			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
12771da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_max, buf, len);
12781da177e4SLinus Torvalds 			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
12791da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_max;
12801da177e4SLinus Torvalds 		}
12811da177e4SLinus Torvalds 		if (debug)
128225a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
1283222f1806SLuiz Capitulino 			       pkt_dev->dst_max);
12841da177e4SLinus Torvalds 		i += len;
12851da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
12861da177e4SLinus Torvalds 		return count;
12871da177e4SLinus Torvalds 	}
12881da177e4SLinus Torvalds 	if (!strcmp(name, "dst6")) {
12891da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1290222f1806SLuiz Capitulino 		if (len < 0)
1291222f1806SLuiz Capitulino 			return len;
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12961da177e4SLinus Torvalds 			return -EFAULT;
12971da177e4SLinus Torvalds 		buf[len] = 0;
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
13001da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
13011da177e4SLinus Torvalds 
13021da177e4SLinus Torvalds 		ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
13031da177e4SLinus Torvalds 
13041da177e4SLinus Torvalds 		if (debug)
130525a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds 		i += len;
13081da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6=%s", buf);
13091da177e4SLinus Torvalds 		return count;
13101da177e4SLinus Torvalds 	}
13111da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_min")) {
13121da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1313222f1806SLuiz Capitulino 		if (len < 0)
1314222f1806SLuiz Capitulino 			return len;
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13191da177e4SLinus Torvalds 			return -EFAULT;
13201da177e4SLinus Torvalds 		buf[len] = 0;
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
13231da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
13241da177e4SLinus Torvalds 
1325222f1806SLuiz Capitulino 		ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
1326222f1806SLuiz Capitulino 			       &pkt_dev->min_in6_daddr);
13271da177e4SLinus Torvalds 		if (debug)
132825a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
13291da177e4SLinus Torvalds 
13301da177e4SLinus Torvalds 		i += len;
13311da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_min=%s", buf);
13321da177e4SLinus Torvalds 		return count;
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_max")) {
13351da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1336222f1806SLuiz Capitulino 		if (len < 0)
1337222f1806SLuiz Capitulino 			return len;
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13421da177e4SLinus Torvalds 			return -EFAULT;
13431da177e4SLinus Torvalds 		buf[len] = 0;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
13461da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 		if (debug)
134925a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 		i += len;
13521da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_max=%s", buf);
13531da177e4SLinus Torvalds 		return count;
13541da177e4SLinus Torvalds 	}
13551da177e4SLinus Torvalds 	if (!strcmp(name, "src6")) {
13561da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1357222f1806SLuiz Capitulino 		if (len < 0)
1358222f1806SLuiz Capitulino 			return len;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13631da177e4SLinus Torvalds 			return -EFAULT;
13641da177e4SLinus Torvalds 		buf[len] = 0;
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
13671da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 		ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds 		if (debug)
137225a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds 		i += len;
13751da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src6=%s", buf);
13761da177e4SLinus Torvalds 		return count;
13771da177e4SLinus Torvalds 	}
13781da177e4SLinus Torvalds 	if (!strcmp(name, "src_min")) {
13791da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
138063adc6fbSStephen Hemminger 		if (len < 0)
1381222f1806SLuiz Capitulino 			return len;
138263adc6fbSStephen Hemminger 
13831da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13841da177e4SLinus Torvalds 			return -EFAULT;
13851da177e4SLinus Torvalds 		buf[len] = 0;
13861da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_min) != 0) {
13871da177e4SLinus Torvalds 			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
13881da177e4SLinus Torvalds 			strncpy(pkt_dev->src_min, buf, len);
13891da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
13901da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_min;
13911da177e4SLinus Torvalds 		}
13921da177e4SLinus Torvalds 		if (debug)
139325a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
1394222f1806SLuiz Capitulino 			       pkt_dev->src_min);
13951da177e4SLinus Torvalds 		i += len;
13961da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
13971da177e4SLinus Torvalds 		return count;
13981da177e4SLinus Torvalds 	}
13991da177e4SLinus Torvalds 	if (!strcmp(name, "src_max")) {
14001da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
140163adc6fbSStephen Hemminger 		if (len < 0)
1402222f1806SLuiz Capitulino 			return len;
140363adc6fbSStephen Hemminger 
14041da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14051da177e4SLinus Torvalds 			return -EFAULT;
14061da177e4SLinus Torvalds 		buf[len] = 0;
14071da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_max) != 0) {
14081da177e4SLinus Torvalds 			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
14091da177e4SLinus Torvalds 			strncpy(pkt_dev->src_max, buf, len);
14101da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
14111da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_max;
14121da177e4SLinus Torvalds 		}
14131da177e4SLinus Torvalds 		if (debug)
141425a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
1415222f1806SLuiz Capitulino 			       pkt_dev->src_max);
14161da177e4SLinus Torvalds 		i += len;
14171da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
14181da177e4SLinus Torvalds 		return count;
14191da177e4SLinus Torvalds 	}
14201da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac")) {
14211da177e4SLinus Torvalds 		char *v = valstr;
1422f404e9a6SKris Katterjohn 		unsigned char old_dmac[ETH_ALEN];
14231da177e4SLinus Torvalds 		unsigned char *m = pkt_dev->dst_mac;
1424f404e9a6SKris Katterjohn 		memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
142763adc6fbSStephen Hemminger 		if (len < 0)
1428222f1806SLuiz Capitulino 			return len;
142963adc6fbSStephen Hemminger 
14301da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14311da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14321da177e4SLinus Torvalds 			return -EFAULT;
14331da177e4SLinus Torvalds 		i += len;
14341da177e4SLinus Torvalds 
14351da177e4SLinus Torvalds 		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
1436451e07a2SAndy Shevchenko 			int value;
1437451e07a2SAndy Shevchenko 
1438451e07a2SAndy Shevchenko 			value = hex_to_bin(*v);
1439451e07a2SAndy Shevchenko 			if (value >= 0)
1440451e07a2SAndy Shevchenko 				*m = *m * 16 + value;
1441451e07a2SAndy Shevchenko 
14421da177e4SLinus Torvalds 			if (*v == ':') {
14431da177e4SLinus Torvalds 				m++;
14441da177e4SLinus Torvalds 				*m = 0;
14451da177e4SLinus Torvalds 			}
14461da177e4SLinus Torvalds 		}
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds 		/* Set up Dest MAC */
1449f404e9a6SKris Katterjohn 		if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
1450f404e9a6SKris Katterjohn 			memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dstmac");
14531da177e4SLinus Torvalds 		return count;
14541da177e4SLinus Torvalds 	}
14551da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac")) {
14561da177e4SLinus Torvalds 		char *v = valstr;
1457ce5d0b47SAdit Ranadive 		unsigned char old_smac[ETH_ALEN];
14581da177e4SLinus Torvalds 		unsigned char *m = pkt_dev->src_mac;
14591da177e4SLinus Torvalds 
1460ce5d0b47SAdit Ranadive 		memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
1461ce5d0b47SAdit Ranadive 
14621da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
146363adc6fbSStephen Hemminger 		if (len < 0)
1464222f1806SLuiz Capitulino 			return len;
146563adc6fbSStephen Hemminger 
14661da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14671da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14681da177e4SLinus Torvalds 			return -EFAULT;
14691da177e4SLinus Torvalds 		i += len;
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds 		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
1472451e07a2SAndy Shevchenko 			int value;
1473451e07a2SAndy Shevchenko 
1474451e07a2SAndy Shevchenko 			value = hex_to_bin(*v);
1475451e07a2SAndy Shevchenko 			if (value >= 0)
1476451e07a2SAndy Shevchenko 				*m = *m * 16 + value;
1477451e07a2SAndy Shevchenko 
14781da177e4SLinus Torvalds 			if (*v == ':') {
14791da177e4SLinus Torvalds 				m++;
14801da177e4SLinus Torvalds 				*m = 0;
14811da177e4SLinus Torvalds 			}
14821da177e4SLinus Torvalds 		}
14831da177e4SLinus Torvalds 
1484ce5d0b47SAdit Ranadive 		/* Set up Src MAC */
1485ce5d0b47SAdit Ranadive 		if (compare_ether_addr(old_smac, pkt_dev->src_mac))
1486ce5d0b47SAdit Ranadive 			memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
1487ce5d0b47SAdit Ranadive 
14881da177e4SLinus Torvalds 		sprintf(pg_result, "OK: srcmac");
14891da177e4SLinus Torvalds 		return count;
14901da177e4SLinus Torvalds 	}
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds 	if (!strcmp(name, "clear_counters")) {
14931da177e4SLinus Torvalds 		pktgen_clear_counters(pkt_dev);
14941da177e4SLinus Torvalds 		sprintf(pg_result, "OK: Clearing counters.\n");
14951da177e4SLinus Torvalds 		return count;
14961da177e4SLinus Torvalds 	}
14971da177e4SLinus Torvalds 
14981da177e4SLinus Torvalds 	if (!strcmp(name, "flows")) {
14991da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
150063adc6fbSStephen Hemminger 		if (len < 0)
1501222f1806SLuiz Capitulino 			return len;
150263adc6fbSStephen Hemminger 
15031da177e4SLinus Torvalds 		i += len;
15041da177e4SLinus Torvalds 		if (value > MAX_CFLOWS)
15051da177e4SLinus Torvalds 			value = MAX_CFLOWS;
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds 		pkt_dev->cflows = value;
15081da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
15091da177e4SLinus Torvalds 		return count;
15101da177e4SLinus Torvalds 	}
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	if (!strcmp(name, "flowlen")) {
15131da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
151463adc6fbSStephen Hemminger 		if (len < 0)
1515222f1806SLuiz Capitulino 			return len;
151663adc6fbSStephen Hemminger 
15171da177e4SLinus Torvalds 		i += len;
15181da177e4SLinus Torvalds 		pkt_dev->lflow = value;
15191da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
15201da177e4SLinus Torvalds 		return count;
15211da177e4SLinus Torvalds 	}
15221da177e4SLinus Torvalds 
152345b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_min")) {
152445b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
152563adc6fbSStephen Hemminger 		if (len < 0)
152645b270f8SRobert Olsson 			return len;
152763adc6fbSStephen Hemminger 
152845b270f8SRobert Olsson 		i += len;
152945b270f8SRobert Olsson 		pkt_dev->queue_map_min = value;
153045b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
153145b270f8SRobert Olsson 		return count;
153245b270f8SRobert Olsson 	}
153345b270f8SRobert Olsson 
153445b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_max")) {
153545b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
153663adc6fbSStephen Hemminger 		if (len < 0)
153745b270f8SRobert Olsson 			return len;
153863adc6fbSStephen Hemminger 
153945b270f8SRobert Olsson 		i += len;
154045b270f8SRobert Olsson 		pkt_dev->queue_map_max = value;
154145b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
154245b270f8SRobert Olsson 		return count;
154345b270f8SRobert Olsson 	}
154445b270f8SRobert Olsson 
1545ca6549afSSteven Whitehouse 	if (!strcmp(name, "mpls")) {
1546cfcabdccSStephen Hemminger 		unsigned n, cnt;
1547cfcabdccSStephen Hemminger 
1548ca6549afSSteven Whitehouse 		len = get_labels(&user_buffer[i], pkt_dev);
1549cfcabdccSStephen Hemminger 		if (len < 0)
1550cfcabdccSStephen Hemminger 			return len;
1551ca6549afSSteven Whitehouse 		i += len;
1552cfcabdccSStephen Hemminger 		cnt = sprintf(pg_result, "OK: mpls=");
1553ca6549afSSteven Whitehouse 		for (n = 0; n < pkt_dev->nr_labels; n++)
1554cfcabdccSStephen Hemminger 			cnt += sprintf(pg_result + cnt,
1555ca6549afSSteven Whitehouse 				       "%08x%s", ntohl(pkt_dev->labels[n]),
1556ca6549afSSteven Whitehouse 				       n == pkt_dev->nr_labels-1 ? "" : ",");
155734954ddcSFrancesco Fondelli 
155834954ddcSFrancesco Fondelli 		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
155934954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
156034954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
156134954ddcSFrancesco Fondelli 
156234954ddcSFrancesco Fondelli 			if (debug)
156325a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
156434954ddcSFrancesco Fondelli 		}
156534954ddcSFrancesco Fondelli 		return count;
156634954ddcSFrancesco Fondelli 	}
156734954ddcSFrancesco Fondelli 
156834954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_id")) {
156934954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
157063adc6fbSStephen Hemminger 		if (len < 0)
157134954ddcSFrancesco Fondelli 			return len;
157263adc6fbSStephen Hemminger 
157334954ddcSFrancesco Fondelli 		i += len;
157434954ddcSFrancesco Fondelli 		if (value <= 4095) {
157534954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = value;  /* turn on VLAN */
157634954ddcSFrancesco Fondelli 
157734954ddcSFrancesco Fondelli 			if (debug)
157825a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN turned on\n");
157934954ddcSFrancesco Fondelli 
158034954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
158125a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
158234954ddcSFrancesco Fondelli 
158334954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
158434954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
158534954ddcSFrancesco Fondelli 		} else {
158634954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
158734954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
158834954ddcSFrancesco Fondelli 
158934954ddcSFrancesco Fondelli 			if (debug)
159025a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
159134954ddcSFrancesco Fondelli 		}
159234954ddcSFrancesco Fondelli 		return count;
159334954ddcSFrancesco Fondelli 	}
159434954ddcSFrancesco Fondelli 
159534954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_p")) {
159634954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
159763adc6fbSStephen Hemminger 		if (len < 0)
159834954ddcSFrancesco Fondelli 			return len;
159963adc6fbSStephen Hemminger 
160034954ddcSFrancesco Fondelli 		i += len;
160134954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
160234954ddcSFrancesco Fondelli 			pkt_dev->vlan_p = value;
160334954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
160434954ddcSFrancesco Fondelli 		} else {
160534954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
160634954ddcSFrancesco Fondelli 		}
160734954ddcSFrancesco Fondelli 		return count;
160834954ddcSFrancesco Fondelli 	}
160934954ddcSFrancesco Fondelli 
161034954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_cfi")) {
161134954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
161263adc6fbSStephen Hemminger 		if (len < 0)
161334954ddcSFrancesco Fondelli 			return len;
161463adc6fbSStephen Hemminger 
161534954ddcSFrancesco Fondelli 		i += len;
161634954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
161734954ddcSFrancesco Fondelli 			pkt_dev->vlan_cfi = value;
161834954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
161934954ddcSFrancesco Fondelli 		} else {
162034954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
162134954ddcSFrancesco Fondelli 		}
162234954ddcSFrancesco Fondelli 		return count;
162334954ddcSFrancesco Fondelli 	}
162434954ddcSFrancesco Fondelli 
162534954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_id")) {
162634954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
162763adc6fbSStephen Hemminger 		if (len < 0)
162834954ddcSFrancesco Fondelli 			return len;
162963adc6fbSStephen Hemminger 
163034954ddcSFrancesco Fondelli 		i += len;
163134954ddcSFrancesco Fondelli 		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
163234954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = value;  /* turn on SVLAN */
163334954ddcSFrancesco Fondelli 
163434954ddcSFrancesco Fondelli 			if (debug)
163525a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
163634954ddcSFrancesco Fondelli 
163734954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
163825a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
163934954ddcSFrancesco Fondelli 
164034954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
164134954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
164234954ddcSFrancesco Fondelli 		} else {
164334954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
164434954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
164534954ddcSFrancesco Fondelli 
164634954ddcSFrancesco Fondelli 			if (debug)
164725a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
164834954ddcSFrancesco Fondelli 		}
164934954ddcSFrancesco Fondelli 		return count;
165034954ddcSFrancesco Fondelli 	}
165134954ddcSFrancesco Fondelli 
165234954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_p")) {
165334954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
165463adc6fbSStephen Hemminger 		if (len < 0)
165534954ddcSFrancesco Fondelli 			return len;
165663adc6fbSStephen Hemminger 
165734954ddcSFrancesco Fondelli 		i += len;
165834954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
165934954ddcSFrancesco Fondelli 			pkt_dev->svlan_p = value;
166034954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
166134954ddcSFrancesco Fondelli 		} else {
166234954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
166334954ddcSFrancesco Fondelli 		}
166434954ddcSFrancesco Fondelli 		return count;
166534954ddcSFrancesco Fondelli 	}
166634954ddcSFrancesco Fondelli 
166734954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_cfi")) {
166834954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
166963adc6fbSStephen Hemminger 		if (len < 0)
167034954ddcSFrancesco Fondelli 			return len;
167163adc6fbSStephen Hemminger 
167234954ddcSFrancesco Fondelli 		i += len;
167334954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
167434954ddcSFrancesco Fondelli 			pkt_dev->svlan_cfi = value;
167534954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
167634954ddcSFrancesco Fondelli 		} else {
167734954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
167834954ddcSFrancesco Fondelli 		}
1679ca6549afSSteven Whitehouse 		return count;
1680ca6549afSSteven Whitehouse 	}
1681ca6549afSSteven Whitehouse 
16821ca7768cSFrancesco Fondelli 	if (!strcmp(name, "tos")) {
16831ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
16841ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
168563adc6fbSStephen Hemminger 		if (len < 0)
16861ca7768cSFrancesco Fondelli 			return len;
168763adc6fbSStephen Hemminger 
16881ca7768cSFrancesco Fondelli 		i += len;
16891ca7768cSFrancesco Fondelli 		if (len == 2) {
16901ca7768cSFrancesco Fondelli 			pkt_dev->tos = tmp_value;
16911ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
16921ca7768cSFrancesco Fondelli 		} else {
16931ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: tos must be 00-ff");
16941ca7768cSFrancesco Fondelli 		}
16951ca7768cSFrancesco Fondelli 		return count;
16961ca7768cSFrancesco Fondelli 	}
16971ca7768cSFrancesco Fondelli 
16981ca7768cSFrancesco Fondelli 	if (!strcmp(name, "traffic_class")) {
16991ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
17001ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
170163adc6fbSStephen Hemminger 		if (len < 0)
17021ca7768cSFrancesco Fondelli 			return len;
170363adc6fbSStephen Hemminger 
17041ca7768cSFrancesco Fondelli 		i += len;
17051ca7768cSFrancesco Fondelli 		if (len == 2) {
17061ca7768cSFrancesco Fondelli 			pkt_dev->traffic_class = tmp_value;
17071ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
17081ca7768cSFrancesco Fondelli 		} else {
17091ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
17101ca7768cSFrancesco Fondelli 		}
17111ca7768cSFrancesco Fondelli 		return count;
17121ca7768cSFrancesco Fondelli 	}
17131ca7768cSFrancesco Fondelli 
17141da177e4SLinus Torvalds 	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
17151da177e4SLinus Torvalds 	return -EINVAL;
17161da177e4SLinus Torvalds }
17171da177e4SLinus Torvalds 
1718d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file)
17191da177e4SLinus Torvalds {
1720d50a6b56SStephen Hemminger 	return single_open(file, pktgen_if_show, PDE(inode)->data);
17211da177e4SLinus Torvalds }
17221da177e4SLinus Torvalds 
17239a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = {
1724d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1725d50a6b56SStephen Hemminger 	.open    = pktgen_if_open,
1726d50a6b56SStephen Hemminger 	.read    = seq_read,
1727d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1728d50a6b56SStephen Hemminger 	.write   = pktgen_if_write,
1729d50a6b56SStephen Hemminger 	.release = single_release,
1730d50a6b56SStephen Hemminger };
1731d50a6b56SStephen Hemminger 
1732d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v)
1733d50a6b56SStephen Hemminger {
1734d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1735648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
1736d50a6b56SStephen Hemminger 
1737d50a6b56SStephen Hemminger 	BUG_ON(!t);
1738d50a6b56SStephen Hemminger 
1739d50a6b56SStephen Hemminger 	seq_printf(seq, "Running: ");
17401da177e4SLinus Torvalds 
17411da177e4SLinus Torvalds 	if_lock(t);
1742c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
17431da177e4SLinus Torvalds 		if (pkt_dev->running)
1744593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17451da177e4SLinus Torvalds 
1746d50a6b56SStephen Hemminger 	seq_printf(seq, "\nStopped: ");
17471da177e4SLinus Torvalds 
1748c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
17491da177e4SLinus Torvalds 		if (!pkt_dev->running)
1750593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17511da177e4SLinus Torvalds 
17521da177e4SLinus Torvalds 	if (t->result[0])
1753d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: %s\n", t->result);
17541da177e4SLinus Torvalds 	else
1755d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: NA\n");
17561da177e4SLinus Torvalds 
17571da177e4SLinus Torvalds 	if_unlock(t);
17581da177e4SLinus Torvalds 
1759d50a6b56SStephen Hemminger 	return 0;
17601da177e4SLinus Torvalds }
17611da177e4SLinus Torvalds 
1762d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file,
1763d50a6b56SStephen Hemminger 				   const char __user * user_buffer,
1764d50a6b56SStephen Hemminger 				   size_t count, loff_t * offset)
17651da177e4SLinus Torvalds {
17668a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
1767d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1768d6182223SPaul Gortmaker 	int i, max, len, ret;
17691da177e4SLinus Torvalds 	char name[40];
17701da177e4SLinus Torvalds 	char *pg_result;
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds 	if (count < 1) {
17731da177e4SLinus Torvalds 		//      sprintf(pg_result, "Wrong command format");
17741da177e4SLinus Torvalds 		return -EINVAL;
17751da177e4SLinus Torvalds 	}
17761da177e4SLinus Torvalds 
1777d6182223SPaul Gortmaker 	max = count;
1778d6182223SPaul Gortmaker 	len = count_trail_chars(user_buffer, max);
17791da177e4SLinus Torvalds 	if (len < 0)
17801da177e4SLinus Torvalds 		return len;
17811da177e4SLinus Torvalds 
1782d6182223SPaul Gortmaker 	i = len;
17831da177e4SLinus Torvalds 
17841da177e4SLinus Torvalds 	/* Read variable name */
17851da177e4SLinus Torvalds 
17861da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
17871da177e4SLinus Torvalds 	if (len < 0)
17881da177e4SLinus Torvalds 		return len;
17891da177e4SLinus Torvalds 
17901da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
17911da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
17921da177e4SLinus Torvalds 		return -EFAULT;
17931da177e4SLinus Torvalds 	i += len;
17941da177e4SLinus Torvalds 
17951da177e4SLinus Torvalds 	max = count - i;
17961da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
17971da177e4SLinus Torvalds 	if (len < 0)
17981da177e4SLinus Torvalds 		return len;
17991da177e4SLinus Torvalds 
18001da177e4SLinus Torvalds 	i += len;
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds 	if (debug)
180325a8b254SDavid S. Miller 		printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
180425a8b254SDavid S. Miller 		       name, (unsigned long)count);
18051da177e4SLinus Torvalds 
18061da177e4SLinus Torvalds 	if (!t) {
1807f9467eaeSJoe Perches 		pr_err("ERROR: No thread\n");
18081da177e4SLinus Torvalds 		ret = -EINVAL;
18091da177e4SLinus Torvalds 		goto out;
18101da177e4SLinus Torvalds 	}
18111da177e4SLinus Torvalds 
18121da177e4SLinus Torvalds 	pg_result = &(t->result[0]);
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds 	if (!strcmp(name, "add_device")) {
18151da177e4SLinus Torvalds 		char f[32];
18161da177e4SLinus Torvalds 		memset(f, 0, 32);
18171da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
18181da177e4SLinus Torvalds 		if (len < 0) {
18191da177e4SLinus Torvalds 			ret = len;
18201da177e4SLinus Torvalds 			goto out;
18211da177e4SLinus Torvalds 		}
18221da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
18231da177e4SLinus Torvalds 			return -EFAULT;
18241da177e4SLinus Torvalds 		i += len;
18256146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
18261da177e4SLinus Torvalds 		pktgen_add_device(t, f);
18276146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
18281da177e4SLinus Torvalds 		ret = count;
18291da177e4SLinus Torvalds 		sprintf(pg_result, "OK: add_device=%s", f);
18301da177e4SLinus Torvalds 		goto out;
18311da177e4SLinus Torvalds 	}
18321da177e4SLinus Torvalds 
18331da177e4SLinus Torvalds 	if (!strcmp(name, "rem_device_all")) {
18346146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
183595ed63f7SArthur Kepner 		t->control |= T_REMDEVALL;
18366146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1837121caf57SNishanth Aravamudan 		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
18381da177e4SLinus Torvalds 		ret = count;
18391da177e4SLinus Torvalds 		sprintf(pg_result, "OK: rem_device_all");
18401da177e4SLinus Torvalds 		goto out;
18411da177e4SLinus Torvalds 	}
18421da177e4SLinus Torvalds 
18431da177e4SLinus Torvalds 	if (!strcmp(name, "max_before_softirq")) {
1844b163911fSRobert Olsson 		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
18451da177e4SLinus Torvalds 		ret = count;
18461da177e4SLinus Torvalds 		goto out;
18471da177e4SLinus Torvalds 	}
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 	ret = -EINVAL;
18501da177e4SLinus Torvalds out:
18511da177e4SLinus Torvalds 	return ret;
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
1854d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file)
18551da177e4SLinus Torvalds {
1856d50a6b56SStephen Hemminger 	return single_open(file, pktgen_thread_show, PDE(inode)->data);
18571da177e4SLinus Torvalds }
18581da177e4SLinus Torvalds 
18599a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = {
1860d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1861d50a6b56SStephen Hemminger 	.open    = pktgen_thread_open,
1862d50a6b56SStephen Hemminger 	.read    = seq_read,
1863d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1864d50a6b56SStephen Hemminger 	.write   = pktgen_thread_write,
1865d50a6b56SStephen Hemminger 	.release = single_release,
1866d50a6b56SStephen Hemminger };
18671da177e4SLinus Torvalds 
18681da177e4SLinus Torvalds /* Think find or remove for NN */
18691da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
18701da177e4SLinus Torvalds {
18711da177e4SLinus Torvalds 	struct pktgen_thread *t;
18721da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
18733e984840SEric Dumazet 	bool exact = (remove == FIND);
18741da177e4SLinus Torvalds 
1875cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list) {
18763e984840SEric Dumazet 		pkt_dev = pktgen_find_dev(t, ifname, exact);
18771da177e4SLinus Torvalds 		if (pkt_dev) {
18781da177e4SLinus Torvalds 			if (remove) {
18791da177e4SLinus Torvalds 				if_lock(t);
188095ed63f7SArthur Kepner 				pkt_dev->removal_mark = 1;
188195ed63f7SArthur Kepner 				t->control |= T_REMDEV;
18821da177e4SLinus Torvalds 				if_unlock(t);
18831da177e4SLinus Torvalds 			}
18841da177e4SLinus Torvalds 			break;
18851da177e4SLinus Torvalds 		}
18861da177e4SLinus Torvalds 	}
18871da177e4SLinus Torvalds 	return pkt_dev;
18881da177e4SLinus Torvalds }
18891da177e4SLinus Torvalds 
189095ed63f7SArthur Kepner /*
189195ed63f7SArthur Kepner  * mark a device for removal
189295ed63f7SArthur Kepner  */
189339df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname)
18941da177e4SLinus Torvalds {
18951da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
189695ed63f7SArthur Kepner 	const int max_tries = 10, msec_per_try = 125;
189795ed63f7SArthur Kepner 	int i = 0;
189895ed63f7SArthur Kepner 
18996146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
1900f9467eaeSJoe Perches 	pr_debug("%s: marking %s for removal\n", __func__, ifname);
190195ed63f7SArthur Kepner 
190295ed63f7SArthur Kepner 	while (1) {
190395ed63f7SArthur Kepner 
190495ed63f7SArthur Kepner 		pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
1905222f1806SLuiz Capitulino 		if (pkt_dev == NULL)
1906222f1806SLuiz Capitulino 			break;	/* success */
190795ed63f7SArthur Kepner 
19086146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1909f9467eaeSJoe Perches 		pr_debug("%s: waiting for %s to disappear....\n",
1910f9467eaeSJoe Perches 			 __func__, ifname);
191195ed63f7SArthur Kepner 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
19126146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
191395ed63f7SArthur Kepner 
191495ed63f7SArthur Kepner 		if (++i >= max_tries) {
1915f9467eaeSJoe Perches 			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
1916f9467eaeSJoe Perches 			       __func__, msec_per_try * i, ifname);
191795ed63f7SArthur Kepner 			break;
191895ed63f7SArthur Kepner 		}
191995ed63f7SArthur Kepner 
192095ed63f7SArthur Kepner 	}
192195ed63f7SArthur Kepner 
19226146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
192339df232fSStephen Hemminger }
192495ed63f7SArthur Kepner 
192539df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev)
192639df232fSStephen Hemminger {
192739df232fSStephen Hemminger 	struct pktgen_thread *t;
192839df232fSStephen Hemminger 
192939df232fSStephen Hemminger 	list_for_each_entry(t, &pktgen_threads, th_list) {
193039df232fSStephen Hemminger 		struct pktgen_dev *pkt_dev;
193139df232fSStephen Hemminger 
193239df232fSStephen Hemminger 		list_for_each_entry(pkt_dev, &t->if_list, list) {
193339df232fSStephen Hemminger 			if (pkt_dev->odev != dev)
193439df232fSStephen Hemminger 				continue;
193539df232fSStephen Hemminger 
193639df232fSStephen Hemminger 			remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
193739df232fSStephen Hemminger 
19382975315bSAlexey Dobriyan 			pkt_dev->entry = proc_create_data(dev->name, 0600,
19392975315bSAlexey Dobriyan 							  pg_proc_dir,
19402975315bSAlexey Dobriyan 							  &pktgen_if_fops,
19412975315bSAlexey Dobriyan 							  pkt_dev);
194239df232fSStephen Hemminger 			if (!pkt_dev->entry)
1943f9467eaeSJoe Perches 				pr_err("can't move proc entry for '%s'\n",
1944f9467eaeSJoe Perches 				       dev->name);
194539df232fSStephen Hemminger 			break;
194639df232fSStephen Hemminger 		}
194739df232fSStephen Hemminger 	}
19481da177e4SLinus Torvalds }
19491da177e4SLinus Torvalds 
1950222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused,
1951222f1806SLuiz Capitulino 			       unsigned long event, void *ptr)
19521da177e4SLinus Torvalds {
195339df232fSStephen Hemminger 	struct net_device *dev = ptr;
19541da177e4SLinus Torvalds 
1955721499e8SYOSHIFUJI Hideaki 	if (!net_eq(dev_net(dev), &init_net))
1956e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
1957e9dc8653SEric W. Biederman 
19581da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
19591da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
19601da177e4SLinus Torvalds 	 */
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 	switch (event) {
196339df232fSStephen Hemminger 	case NETDEV_CHANGENAME:
196439df232fSStephen Hemminger 		pktgen_change_name(dev);
19651da177e4SLinus Torvalds 		break;
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
196895ed63f7SArthur Kepner 		pktgen_mark_device(dev->name);
19691da177e4SLinus Torvalds 		break;
19703ff50b79SStephen Hemminger 	}
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds 	return NOTIFY_DONE;
19731da177e4SLinus Torvalds }
19741da177e4SLinus Torvalds 
197563adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
197663adc6fbSStephen Hemminger 						 const char *ifname)
1977e6fce5b9SRobert Olsson {
1978e6fce5b9SRobert Olsson 	char b[IFNAMSIZ+5];
1979d6182223SPaul Gortmaker 	int i;
1980e6fce5b9SRobert Olsson 
1981e6fce5b9SRobert Olsson 	for (i = 0; ifname[i] != '@'; i++) {
1982e6fce5b9SRobert Olsson 		if (i == IFNAMSIZ)
1983e6fce5b9SRobert Olsson 			break;
1984e6fce5b9SRobert Olsson 
1985e6fce5b9SRobert Olsson 		b[i] = ifname[i];
1986e6fce5b9SRobert Olsson 	}
1987e6fce5b9SRobert Olsson 	b[i] = 0;
1988e6fce5b9SRobert Olsson 
1989e6fce5b9SRobert Olsson 	return dev_get_by_name(&init_net, b);
1990e6fce5b9SRobert Olsson }
1991e6fce5b9SRobert Olsson 
1992e6fce5b9SRobert Olsson 
19931da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */
19941da177e4SLinus Torvalds 
199539df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
1996222f1806SLuiz Capitulino {
19971da177e4SLinus Torvalds 	struct net_device *odev;
199839df232fSStephen Hemminger 	int err;
19991da177e4SLinus Torvalds 
20001da177e4SLinus Torvalds 	/* Clean old setups */
20011da177e4SLinus Torvalds 	if (pkt_dev->odev) {
20021da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
20031da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
20041da177e4SLinus Torvalds 	}
20051da177e4SLinus Torvalds 
2006e6fce5b9SRobert Olsson 	odev = pktgen_dev_get_by_name(pkt_dev, ifname);
20071da177e4SLinus Torvalds 	if (!odev) {
2008f9467eaeSJoe Perches 		pr_err("no such netdevice: \"%s\"\n", ifname);
200939df232fSStephen Hemminger 		return -ENODEV;
20101da177e4SLinus Torvalds 	}
201139df232fSStephen Hemminger 
20121da177e4SLinus Torvalds 	if (odev->type != ARPHRD_ETHER) {
2013f9467eaeSJoe Perches 		pr_err("not an ethernet device: \"%s\"\n", ifname);
201439df232fSStephen Hemminger 		err = -EINVAL;
201539df232fSStephen Hemminger 	} else if (!netif_running(odev)) {
2016f9467eaeSJoe Perches 		pr_err("device is down: \"%s\"\n", ifname);
201739df232fSStephen Hemminger 		err = -ENETDOWN;
201839df232fSStephen Hemminger 	} else {
20191da177e4SLinus Torvalds 		pkt_dev->odev = odev;
202039df232fSStephen Hemminger 		return 0;
202139df232fSStephen Hemminger 	}
20221da177e4SLinus Torvalds 
20231da177e4SLinus Torvalds 	dev_put(odev);
202439df232fSStephen Hemminger 	return err;
20251da177e4SLinus Torvalds }
20261da177e4SLinus Torvalds 
20271da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev
20281da177e4SLinus Torvalds  * structure to have the right information to create/send packets
20291da177e4SLinus Torvalds  */
20301da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
20311da177e4SLinus Torvalds {
203264c00d81SAndrew Gallatin 	int ntxq;
203364c00d81SAndrew Gallatin 
20341da177e4SLinus Torvalds 	if (!pkt_dev->odev) {
2035f9467eaeSJoe Perches 		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
2036222f1806SLuiz Capitulino 		sprintf(pkt_dev->result,
2037222f1806SLuiz Capitulino 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
20381da177e4SLinus Torvalds 		return;
20391da177e4SLinus Torvalds 	}
20401da177e4SLinus Torvalds 
204164c00d81SAndrew Gallatin 	/* make sure that we don't pick a non-existing transmit queue */
204264c00d81SAndrew Gallatin 	ntxq = pkt_dev->odev->real_num_tx_queues;
2043bfdbc0acSRobert Olsson 
204464c00d81SAndrew Gallatin 	if (ntxq <= pkt_dev->queue_map_min) {
2045f9467eaeSJoe Perches 		pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
204688271660SJesse Brandeburg 			   pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
2047593f63b0SEric Dumazet 			   pkt_dev->odevname);
204864c00d81SAndrew Gallatin 		pkt_dev->queue_map_min = ntxq - 1;
204964c00d81SAndrew Gallatin 	}
205088271660SJesse Brandeburg 	if (pkt_dev->queue_map_max >= ntxq) {
2051f9467eaeSJoe Perches 		pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
205288271660SJesse Brandeburg 			   pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
2053593f63b0SEric Dumazet 			   pkt_dev->odevname);
205464c00d81SAndrew Gallatin 		pkt_dev->queue_map_max = ntxq - 1;
205564c00d81SAndrew Gallatin 	}
205664c00d81SAndrew Gallatin 
20571da177e4SLinus Torvalds 	/* Default to the interface's mac if not explicitly set. */
20581da177e4SLinus Torvalds 
2059f404e9a6SKris Katterjohn 	if (is_zero_ether_addr(pkt_dev->src_mac))
2060f404e9a6SKris Katterjohn 		memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
20611da177e4SLinus Torvalds 
20621da177e4SLinus Torvalds 	/* Set up Dest MAC */
2063f404e9a6SKris Katterjohn 	memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
20641da177e4SLinus Torvalds 
20651da177e4SLinus Torvalds 	/* Set up pkt size */
20661da177e4SLinus Torvalds 	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
20671da177e4SLinus Torvalds 
20681da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
20691da177e4SLinus Torvalds 		/*
20701da177e4SLinus Torvalds 		 * Skip this automatic address setting until locks or functions
20711da177e4SLinus Torvalds 		 * gets exported
20721da177e4SLinus Torvalds 		 */
20731da177e4SLinus Torvalds 
20741da177e4SLinus Torvalds #ifdef NOTNOW
20751da177e4SLinus Torvalds 		int i, set = 0, err = 1;
20761da177e4SLinus Torvalds 		struct inet6_dev *idev;
20771da177e4SLinus Torvalds 
20781da177e4SLinus Torvalds 		for (i = 0; i < IN6_ADDR_HSIZE; i++)
20791da177e4SLinus Torvalds 			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
20801da177e4SLinus Torvalds 				set = 1;
20811da177e4SLinus Torvalds 				break;
20821da177e4SLinus Torvalds 			}
20831da177e4SLinus Torvalds 
20841da177e4SLinus Torvalds 		if (!set) {
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 			/*
20871da177e4SLinus Torvalds 			 * Use linklevel address if unconfigured.
20881da177e4SLinus Torvalds 			 *
20891da177e4SLinus Torvalds 			 * use ipv6_get_lladdr if/when it's get exported
20901da177e4SLinus Torvalds 			 */
20911da177e4SLinus Torvalds 
20928814c4b5SYOSHIFUJI Hideaki 			rcu_read_lock();
209363adc6fbSStephen Hemminger 			idev = __in6_dev_get(pkt_dev->odev);
209463adc6fbSStephen Hemminger 			if (idev) {
20951da177e4SLinus Torvalds 				struct inet6_ifaddr *ifp;
20961da177e4SLinus Torvalds 
20971da177e4SLinus Torvalds 				read_lock_bh(&idev->lock);
2098222f1806SLuiz Capitulino 				for (ifp = idev->addr_list; ifp;
2099222f1806SLuiz Capitulino 				     ifp = ifp->if_next) {
2100f64f9e71SJoe Perches 					if (ifp->scope == IFA_LINK &&
2101f64f9e71SJoe Perches 					    !(ifp->flags & IFA_F_TENTATIVE)) {
2102222f1806SLuiz Capitulino 						ipv6_addr_copy(&pkt_dev->
2103222f1806SLuiz Capitulino 							       cur_in6_saddr,
2104222f1806SLuiz Capitulino 							       &ifp->addr);
21051da177e4SLinus Torvalds 						err = 0;
21061da177e4SLinus Torvalds 						break;
21071da177e4SLinus Torvalds 					}
21081da177e4SLinus Torvalds 				}
21091da177e4SLinus Torvalds 				read_unlock_bh(&idev->lock);
21101da177e4SLinus Torvalds 			}
21118814c4b5SYOSHIFUJI Hideaki 			rcu_read_unlock();
2112222f1806SLuiz Capitulino 			if (err)
2113f9467eaeSJoe Perches 				pr_err("ERROR: IPv6 link address not available\n");
21141da177e4SLinus Torvalds 		}
21151da177e4SLinus Torvalds #endif
2116222f1806SLuiz Capitulino 	} else {
21171da177e4SLinus Torvalds 		pkt_dev->saddr_min = 0;
21181da177e4SLinus Torvalds 		pkt_dev->saddr_max = 0;
21191da177e4SLinus Torvalds 		if (strlen(pkt_dev->src_min) == 0) {
21201da177e4SLinus Torvalds 
21211da177e4SLinus Torvalds 			struct in_device *in_dev;
21221da177e4SLinus Torvalds 
21231da177e4SLinus Torvalds 			rcu_read_lock();
2124e5ed6399SHerbert Xu 			in_dev = __in_dev_get_rcu(pkt_dev->odev);
21251da177e4SLinus Torvalds 			if (in_dev) {
21261da177e4SLinus Torvalds 				if (in_dev->ifa_list) {
2127222f1806SLuiz Capitulino 					pkt_dev->saddr_min =
2128222f1806SLuiz Capitulino 					    in_dev->ifa_list->ifa_address;
21291da177e4SLinus Torvalds 					pkt_dev->saddr_max = pkt_dev->saddr_min;
21301da177e4SLinus Torvalds 				}
21311da177e4SLinus Torvalds 			}
21321da177e4SLinus Torvalds 			rcu_read_unlock();
2133222f1806SLuiz Capitulino 		} else {
21341da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
21351da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
21361da177e4SLinus Torvalds 		}
21371da177e4SLinus Torvalds 
21381da177e4SLinus Torvalds 		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
21391da177e4SLinus Torvalds 		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
21401da177e4SLinus Torvalds 	}
21411da177e4SLinus Torvalds 	/* Initialize current values. */
21421da177e4SLinus Torvalds 	pkt_dev->cur_dst_mac_offset = 0;
21431da177e4SLinus Torvalds 	pkt_dev->cur_src_mac_offset = 0;
21441da177e4SLinus Torvalds 	pkt_dev->cur_saddr = pkt_dev->saddr_min;
21451da177e4SLinus Torvalds 	pkt_dev->cur_daddr = pkt_dev->daddr_min;
21461da177e4SLinus Torvalds 	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
21471da177e4SLinus Torvalds 	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
21481da177e4SLinus Torvalds 	pkt_dev->nflows = 0;
21491da177e4SLinus Torvalds }
21501da177e4SLinus Torvalds 
21511da177e4SLinus Torvalds 
2152fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
2153fd29cf72SStephen Hemminger {
2154ef87979cSStephen Hemminger 	ktime_t start_time, end_time;
2155417bc4b8SEric Dumazet 	s64 remaining;
21562bc481cfSStephen Hemminger 	struct hrtimer_sleeper t;
2157fd29cf72SStephen Hemminger 
21582bc481cfSStephen Hemminger 	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
21592bc481cfSStephen Hemminger 	hrtimer_set_expires(&t.timer, spin_until);
2160fd29cf72SStephen Hemminger 
216143d28b65SDaniel Turull 	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2162417bc4b8SEric Dumazet 	if (remaining <= 0) {
2163417bc4b8SEric Dumazet 		pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
21641da177e4SLinus Torvalds 		return;
2165417bc4b8SEric Dumazet 	}
21662bc481cfSStephen Hemminger 
2167ef87979cSStephen Hemminger 	start_time = ktime_now();
216843d28b65SDaniel Turull 	if (remaining < 100000)
216943d28b65SDaniel Turull 		ndelay(remaining);	/* really small just spin */
21702bc481cfSStephen Hemminger 	else {
21712bc481cfSStephen Hemminger 		/* see do_nanosleep */
21722bc481cfSStephen Hemminger 		hrtimer_init_sleeper(&t, current);
21732bc481cfSStephen Hemminger 		do {
21742bc481cfSStephen Hemminger 			set_current_state(TASK_INTERRUPTIBLE);
21752bc481cfSStephen Hemminger 			hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
21762bc481cfSStephen Hemminger 			if (!hrtimer_active(&t.timer))
21772bc481cfSStephen Hemminger 				t.task = NULL;
21782bc481cfSStephen Hemminger 
21792bc481cfSStephen Hemminger 			if (likely(t.task))
21801da177e4SLinus Torvalds 				schedule();
21811da177e4SLinus Torvalds 
21822bc481cfSStephen Hemminger 			hrtimer_cancel(&t.timer);
21832bc481cfSStephen Hemminger 		} while (t.task && pkt_dev->running && !signal_pending(current));
21842bc481cfSStephen Hemminger 		__set_current_state(TASK_RUNNING);
21851da177e4SLinus Torvalds 	}
2186ef87979cSStephen Hemminger 	end_time = ktime_now();
2187ef87979cSStephen Hemminger 
2188ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
218907a0f0f0SDaniel Turull 	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
21901da177e4SLinus Torvalds }
21911da177e4SLinus Torvalds 
219216dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
219316dab72fSJamal Hadi Salim {
2194a553e4a6SJamal Hadi Salim 	pkt_dev->pkt_overhead = 0;
219516dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
219616dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
219716dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
219816dab72fSJamal Hadi Salim }
219916dab72fSJamal Hadi Salim 
2200648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2201007a531bSJamal Hadi Salim {
2202648fda74SStephen Hemminger 	return !!(pkt_dev->flows[flow].flags & F_INIT);
2203007a531bSJamal Hadi Salim }
2204007a531bSJamal Hadi Salim 
2205007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev)
2206007a531bSJamal Hadi Salim {
2207007a531bSJamal Hadi Salim 	int flow = pkt_dev->curfl;
2208007a531bSJamal Hadi Salim 
2209007a531bSJamal Hadi Salim 	if (pkt_dev->flags & F_FLOW_SEQ) {
2210007a531bSJamal Hadi Salim 		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
2211007a531bSJamal Hadi Salim 			/* reset time */
2212007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22131211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
2214007a531bSJamal Hadi Salim 			pkt_dev->curfl += 1;
2215007a531bSJamal Hadi Salim 			if (pkt_dev->curfl >= pkt_dev->cflows)
2216007a531bSJamal Hadi Salim 				pkt_dev->curfl = 0; /*reset */
2217007a531bSJamal Hadi Salim 		}
2218007a531bSJamal Hadi Salim 	} else {
2219007a531bSJamal Hadi Salim 		flow = random32() % pkt_dev->cflows;
22201211a645SRobert Olsson 		pkt_dev->curfl = flow;
2221007a531bSJamal Hadi Salim 
22221211a645SRobert Olsson 		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2223007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22241211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
22251211a645SRobert Olsson 		}
2226007a531bSJamal Hadi Salim 	}
2227007a531bSJamal Hadi Salim 
2228007a531bSJamal Hadi Salim 	return pkt_dev->curfl;
2229007a531bSJamal Hadi Salim }
2230007a531bSJamal Hadi Salim 
2231a553e4a6SJamal Hadi Salim 
2232a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2233a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else
2234a553e4a6SJamal Hadi Salim  * we go look for it ...
2235a553e4a6SJamal Hadi Salim */
2236bd55775cSJamal Hadi Salim #define DUMMY_MARK 0
2237fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
2238a553e4a6SJamal Hadi Salim {
2239a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[flow].x;
2240a553e4a6SJamal Hadi Salim 	if (!x) {
2241a553e4a6SJamal Hadi Salim 		/*slow path: we dont already have xfrm_state*/
2242bd55775cSJamal Hadi Salim 		x = xfrm_stateonly_find(&init_net, DUMMY_MARK,
22435447c5e4SAlexey Dobriyan 					(xfrm_address_t *)&pkt_dev->cur_daddr,
2244a553e4a6SJamal Hadi Salim 					(xfrm_address_t *)&pkt_dev->cur_saddr,
2245a553e4a6SJamal Hadi Salim 					AF_INET,
2246a553e4a6SJamal Hadi Salim 					pkt_dev->ipsmode,
2247a553e4a6SJamal Hadi Salim 					pkt_dev->ipsproto, 0);
2248a553e4a6SJamal Hadi Salim 		if (x) {
2249a553e4a6SJamal Hadi Salim 			pkt_dev->flows[flow].x = x;
2250a553e4a6SJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
2251a553e4a6SJamal Hadi Salim 			pkt_dev->pkt_overhead += x->props.header_len;
2252a553e4a6SJamal Hadi Salim 		}
2253a553e4a6SJamal Hadi Salim 
2254a553e4a6SJamal Hadi Salim 	}
2255a553e4a6SJamal Hadi Salim }
2256a553e4a6SJamal Hadi Salim #endif
2257fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
2258fd2ea0a7SDavid S. Miller {
2259e6fce5b9SRobert Olsson 
2260e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
2261e6fce5b9SRobert Olsson 		pkt_dev->cur_queue_map = smp_processor_id();
2262e6fce5b9SRobert Olsson 
2263896a7cf8SEric Dumazet 	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2264fd2ea0a7SDavid S. Miller 		__u16 t;
2265fd2ea0a7SDavid S. Miller 		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
2266fd2ea0a7SDavid S. Miller 			t = random32() %
2267fd2ea0a7SDavid S. Miller 				(pkt_dev->queue_map_max -
2268fd2ea0a7SDavid S. Miller 				 pkt_dev->queue_map_min + 1)
2269fd2ea0a7SDavid S. Miller 				+ pkt_dev->queue_map_min;
2270fd2ea0a7SDavid S. Miller 		} else {
2271fd2ea0a7SDavid S. Miller 			t = pkt_dev->cur_queue_map + 1;
2272fd2ea0a7SDavid S. Miller 			if (t > pkt_dev->queue_map_max)
2273fd2ea0a7SDavid S. Miller 				t = pkt_dev->queue_map_min;
2274fd2ea0a7SDavid S. Miller 		}
2275fd2ea0a7SDavid S. Miller 		pkt_dev->cur_queue_map = t;
2276fd2ea0a7SDavid S. Miller 	}
2277bfdbc0acSRobert Olsson 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2278fd2ea0a7SDavid S. Miller }
2279fd2ea0a7SDavid S. Miller 
22801da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values
22811da177e4SLinus Torvalds  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
22821da177e4SLinus Torvalds  */
2283222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev)
2284222f1806SLuiz Capitulino {
22851da177e4SLinus Torvalds 	__u32 imn;
22861da177e4SLinus Torvalds 	__u32 imx;
22871da177e4SLinus Torvalds 	int flow = 0;
22881da177e4SLinus Torvalds 
2289007a531bSJamal Hadi Salim 	if (pkt_dev->cflows)
2290007a531bSJamal Hadi Salim 		flow = f_pick(pkt_dev);
22911da177e4SLinus Torvalds 
22921da177e4SLinus Torvalds 	/*  Deal with source MAC */
22931da177e4SLinus Torvalds 	if (pkt_dev->src_mac_count > 1) {
22941da177e4SLinus Torvalds 		__u32 mc;
22951da177e4SLinus Torvalds 		__u32 tmp;
22961da177e4SLinus Torvalds 
22971da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACSRC_RND)
22985fa6fc76SStephen Hemminger 			mc = random32() % pkt_dev->src_mac_count;
22991da177e4SLinus Torvalds 		else {
23001da177e4SLinus Torvalds 			mc = pkt_dev->cur_src_mac_offset++;
2301ff2a79a5SRobert Olsson 			if (pkt_dev->cur_src_mac_offset >=
2302222f1806SLuiz Capitulino 			    pkt_dev->src_mac_count)
23031da177e4SLinus Torvalds 				pkt_dev->cur_src_mac_offset = 0;
23041da177e4SLinus Torvalds 		}
23051da177e4SLinus Torvalds 
23061da177e4SLinus Torvalds 		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
23071da177e4SLinus Torvalds 		pkt_dev->hh[11] = tmp;
23081da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23091da177e4SLinus Torvalds 		pkt_dev->hh[10] = tmp;
23101da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23111da177e4SLinus Torvalds 		pkt_dev->hh[9] = tmp;
23121da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23131da177e4SLinus Torvalds 		pkt_dev->hh[8] = tmp;
23141da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
23151da177e4SLinus Torvalds 		pkt_dev->hh[7] = tmp;
23161da177e4SLinus Torvalds 	}
23171da177e4SLinus Torvalds 
23181da177e4SLinus Torvalds 	/*  Deal with Destination MAC */
23191da177e4SLinus Torvalds 	if (pkt_dev->dst_mac_count > 1) {
23201da177e4SLinus Torvalds 		__u32 mc;
23211da177e4SLinus Torvalds 		__u32 tmp;
23221da177e4SLinus Torvalds 
23231da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACDST_RND)
23245fa6fc76SStephen Hemminger 			mc = random32() % pkt_dev->dst_mac_count;
23251da177e4SLinus Torvalds 
23261da177e4SLinus Torvalds 		else {
23271da177e4SLinus Torvalds 			mc = pkt_dev->cur_dst_mac_offset++;
2328ff2a79a5SRobert Olsson 			if (pkt_dev->cur_dst_mac_offset >=
2329222f1806SLuiz Capitulino 			    pkt_dev->dst_mac_count) {
23301da177e4SLinus Torvalds 				pkt_dev->cur_dst_mac_offset = 0;
23311da177e4SLinus Torvalds 			}
23321da177e4SLinus Torvalds 		}
23331da177e4SLinus Torvalds 
23341da177e4SLinus Torvalds 		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
23351da177e4SLinus Torvalds 		pkt_dev->hh[5] = tmp;
23361da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23371da177e4SLinus Torvalds 		pkt_dev->hh[4] = tmp;
23381da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23391da177e4SLinus Torvalds 		pkt_dev->hh[3] = tmp;
23401da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23411da177e4SLinus Torvalds 		pkt_dev->hh[2] = tmp;
23421da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
23431da177e4SLinus Torvalds 		pkt_dev->hh[1] = tmp;
23441da177e4SLinus Torvalds 	}
23451da177e4SLinus Torvalds 
2346ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND) {
2347ca6549afSSteven Whitehouse 		unsigned i;
2348ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
2349ca6549afSSteven Whitehouse 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
2350ca6549afSSteven Whitehouse 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
23515fa6fc76SStephen Hemminger 					     ((__force __be32)random32() &
2352ca6549afSSteven Whitehouse 						      htonl(0x000fffff));
2353ca6549afSSteven Whitehouse 	}
2354ca6549afSSteven Whitehouse 
235534954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
23565fa6fc76SStephen Hemminger 		pkt_dev->vlan_id = random32() & (4096-1);
235734954ddcSFrancesco Fondelli 	}
235834954ddcSFrancesco Fondelli 
235934954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
23605fa6fc76SStephen Hemminger 		pkt_dev->svlan_id = random32() & (4096 - 1);
236134954ddcSFrancesco Fondelli 	}
236234954ddcSFrancesco Fondelli 
23631da177e4SLinus Torvalds 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
23641da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPSRC_RND)
23655fa6fc76SStephen Hemminger 			pkt_dev->cur_udp_src = random32() %
23665fa6fc76SStephen Hemminger 				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
23675fa6fc76SStephen Hemminger 				+ pkt_dev->udp_src_min;
23681da177e4SLinus Torvalds 
23691da177e4SLinus Torvalds 		else {
23701da177e4SLinus Torvalds 			pkt_dev->cur_udp_src++;
23711da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
23721da177e4SLinus Torvalds 				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
23731da177e4SLinus Torvalds 		}
23741da177e4SLinus Torvalds 	}
23751da177e4SLinus Torvalds 
23761da177e4SLinus Torvalds 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
23771da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPDST_RND) {
23785fa6fc76SStephen Hemminger 			pkt_dev->cur_udp_dst = random32() %
23795fa6fc76SStephen Hemminger 				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
23805fa6fc76SStephen Hemminger 				+ pkt_dev->udp_dst_min;
2381222f1806SLuiz Capitulino 		} else {
23821da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst++;
23831da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
23841da177e4SLinus Torvalds 				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
23851da177e4SLinus Torvalds 		}
23861da177e4SLinus Torvalds 	}
23871da177e4SLinus Torvalds 
23881da177e4SLinus Torvalds 	if (!(pkt_dev->flags & F_IPV6)) {
23891da177e4SLinus Torvalds 
239063adc6fbSStephen Hemminger 		imn = ntohl(pkt_dev->saddr_min);
239163adc6fbSStephen Hemminger 		imx = ntohl(pkt_dev->saddr_max);
239263adc6fbSStephen Hemminger 		if (imn < imx) {
23931da177e4SLinus Torvalds 			__u32 t;
23941da177e4SLinus Torvalds 			if (pkt_dev->flags & F_IPSRC_RND)
23955fa6fc76SStephen Hemminger 				t = random32() % (imx - imn) + imn;
23961da177e4SLinus Torvalds 			else {
23971da177e4SLinus Torvalds 				t = ntohl(pkt_dev->cur_saddr);
23981da177e4SLinus Torvalds 				t++;
239963adc6fbSStephen Hemminger 				if (t > imx)
24001da177e4SLinus Torvalds 					t = imn;
240163adc6fbSStephen Hemminger 
24021da177e4SLinus Torvalds 			}
24031da177e4SLinus Torvalds 			pkt_dev->cur_saddr = htonl(t);
24041da177e4SLinus Torvalds 		}
24051da177e4SLinus Torvalds 
2406007a531bSJamal Hadi Salim 		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
24071da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
24081da177e4SLinus Torvalds 		} else {
2409252e3346SAl Viro 			imn = ntohl(pkt_dev->daddr_min);
2410252e3346SAl Viro 			imx = ntohl(pkt_dev->daddr_max);
2411252e3346SAl Viro 			if (imn < imx) {
24121da177e4SLinus Torvalds 				__u32 t;
2413252e3346SAl Viro 				__be32 s;
24141da177e4SLinus Torvalds 				if (pkt_dev->flags & F_IPDST_RND) {
24151da177e4SLinus Torvalds 
24165fa6fc76SStephen Hemminger 					t = random32() % (imx - imn) + imn;
2417252e3346SAl Viro 					s = htonl(t);
24181da177e4SLinus Torvalds 
241921cf2253SJoe Perches 					while (ipv4_is_loopback(s) ||
242021cf2253SJoe Perches 					       ipv4_is_multicast(s) ||
24211e637c74SJan Engelhardt 					       ipv4_is_lbcast(s) ||
242221cf2253SJoe Perches 					       ipv4_is_zeronet(s) ||
242321cf2253SJoe Perches 					       ipv4_is_local_multicast(s)) {
24245fa6fc76SStephen Hemminger 						t = random32() % (imx - imn) + imn;
2425252e3346SAl Viro 						s = htonl(t);
24261da177e4SLinus Torvalds 					}
2427252e3346SAl Viro 					pkt_dev->cur_daddr = s;
2428252e3346SAl Viro 				} else {
24291da177e4SLinus Torvalds 					t = ntohl(pkt_dev->cur_daddr);
24301da177e4SLinus Torvalds 					t++;
24311da177e4SLinus Torvalds 					if (t > imx) {
24321da177e4SLinus Torvalds 						t = imn;
24331da177e4SLinus Torvalds 					}
24341da177e4SLinus Torvalds 					pkt_dev->cur_daddr = htonl(t);
24351da177e4SLinus Torvalds 				}
24361da177e4SLinus Torvalds 			}
24371da177e4SLinus Torvalds 			if (pkt_dev->cflows) {
2438007a531bSJamal Hadi Salim 				pkt_dev->flows[flow].flags |= F_INIT;
2439222f1806SLuiz Capitulino 				pkt_dev->flows[flow].cur_daddr =
2440222f1806SLuiz Capitulino 				    pkt_dev->cur_daddr;
2441a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2442a553e4a6SJamal Hadi Salim 				if (pkt_dev->flags & F_IPSEC_ON)
2443a553e4a6SJamal Hadi Salim 					get_ipsec_sa(pkt_dev, flow);
2444a553e4a6SJamal Hadi Salim #endif
24451da177e4SLinus Torvalds 				pkt_dev->nflows++;
24461da177e4SLinus Torvalds 			}
24471da177e4SLinus Torvalds 		}
2448222f1806SLuiz Capitulino 	} else {		/* IPV6 * */
2449222f1806SLuiz Capitulino 
24501da177e4SLinus Torvalds 		if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 &&
24511da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[1] == 0 &&
24521da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[2] == 0 &&
24531da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ;
24541da177e4SLinus Torvalds 		else {
24551da177e4SLinus Torvalds 			int i;
24561da177e4SLinus Torvalds 
24571da177e4SLinus Torvalds 			/* Only random destinations yet */
24581da177e4SLinus Torvalds 
24591da177e4SLinus Torvalds 			for (i = 0; i < 4; i++) {
24601da177e4SLinus Torvalds 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
24615fa6fc76SStephen Hemminger 				    (((__force __be32)random32() |
24621da177e4SLinus Torvalds 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
24631da177e4SLinus Torvalds 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
24641da177e4SLinus Torvalds 			}
24651da177e4SLinus Torvalds 		}
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds 
24681da177e4SLinus Torvalds 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
24691da177e4SLinus Torvalds 		__u32 t;
24701da177e4SLinus Torvalds 		if (pkt_dev->flags & F_TXSIZE_RND) {
24715fa6fc76SStephen Hemminger 			t = random32() %
24725fa6fc76SStephen Hemminger 				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
24735fa6fc76SStephen Hemminger 				+ pkt_dev->min_pkt_size;
2474222f1806SLuiz Capitulino 		} else {
24751da177e4SLinus Torvalds 			t = pkt_dev->cur_pkt_size + 1;
24761da177e4SLinus Torvalds 			if (t > pkt_dev->max_pkt_size)
24771da177e4SLinus Torvalds 				t = pkt_dev->min_pkt_size;
24781da177e4SLinus Torvalds 		}
24791da177e4SLinus Torvalds 		pkt_dev->cur_pkt_size = t;
24801da177e4SLinus Torvalds 	}
24811da177e4SLinus Torvalds 
2482fd2ea0a7SDavid S. Miller 	set_cur_queue_map(pkt_dev);
248345b270f8SRobert Olsson 
24841da177e4SLinus Torvalds 	pkt_dev->flows[flow].count++;
24851da177e4SLinus Torvalds }
24861da177e4SLinus Torvalds 
2487a553e4a6SJamal Hadi Salim 
2488a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2489a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
2490a553e4a6SJamal Hadi Salim {
2491a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2492a553e4a6SJamal Hadi Salim 	int err = 0;
2493a553e4a6SJamal Hadi Salim 	struct iphdr *iph;
2494a553e4a6SJamal Hadi Salim 
2495a553e4a6SJamal Hadi Salim 	if (!x)
2496a553e4a6SJamal Hadi Salim 		return 0;
2497a553e4a6SJamal Hadi Salim 	/* XXX: we dont support tunnel mode for now until
2498a553e4a6SJamal Hadi Salim 	 * we resolve the dst issue */
2499a553e4a6SJamal Hadi Salim 	if (x->props.mode != XFRM_MODE_TRANSPORT)
2500a553e4a6SJamal Hadi Salim 		return 0;
2501a553e4a6SJamal Hadi Salim 
2502a553e4a6SJamal Hadi Salim 	spin_lock(&x->lock);
2503a553e4a6SJamal Hadi Salim 	iph = ip_hdr(skb);
2504a553e4a6SJamal Hadi Salim 
250513996378SHerbert Xu 	err = x->outer_mode->output(x, skb);
2506a553e4a6SJamal Hadi Salim 	if (err)
2507a553e4a6SJamal Hadi Salim 		goto error;
2508a553e4a6SJamal Hadi Salim 	err = x->type->output(x, skb);
2509a553e4a6SJamal Hadi Salim 	if (err)
2510a553e4a6SJamal Hadi Salim 		goto error;
2511a553e4a6SJamal Hadi Salim 
2512a553e4a6SJamal Hadi Salim 	x->curlft.bytes += skb->len;
2513a553e4a6SJamal Hadi Salim 	x->curlft.packets++;
2514a553e4a6SJamal Hadi Salim error:
2515a553e4a6SJamal Hadi Salim 	spin_unlock(&x->lock);
2516a553e4a6SJamal Hadi Salim 	return err;
2517a553e4a6SJamal Hadi Salim }
2518a553e4a6SJamal Hadi Salim 
2519475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev)
2520a553e4a6SJamal Hadi Salim {
2521a553e4a6SJamal Hadi Salim 	if (pkt_dev->cflows) {
2522a553e4a6SJamal Hadi Salim 		/* let go of the SAs if we have them */
2523d6182223SPaul Gortmaker 		int i;
2524d6182223SPaul Gortmaker 		for (i = 0; i < pkt_dev->cflows; i++) {
2525a553e4a6SJamal Hadi Salim 			struct xfrm_state *x = pkt_dev->flows[i].x;
2526a553e4a6SJamal Hadi Salim 			if (x) {
2527a553e4a6SJamal Hadi Salim 				xfrm_state_put(x);
2528a553e4a6SJamal Hadi Salim 				pkt_dev->flows[i].x = NULL;
2529a553e4a6SJamal Hadi Salim 			}
2530a553e4a6SJamal Hadi Salim 		}
2531a553e4a6SJamal Hadi Salim 	}
2532a553e4a6SJamal Hadi Salim }
2533a553e4a6SJamal Hadi Salim 
2534475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev,
2535a553e4a6SJamal Hadi Salim 			      struct sk_buff *skb, __be16 protocol)
2536a553e4a6SJamal Hadi Salim {
2537a553e4a6SJamal Hadi Salim 	if (pkt_dev->flags & F_IPSEC_ON) {
2538a553e4a6SJamal Hadi Salim 		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2539a553e4a6SJamal Hadi Salim 		int nhead = 0;
2540a553e4a6SJamal Hadi Salim 		if (x) {
2541a553e4a6SJamal Hadi Salim 			int ret;
2542a553e4a6SJamal Hadi Salim 			__u8 *eth;
2543a553e4a6SJamal Hadi Salim 			nhead = x->props.header_len - skb_headroom(skb);
2544a553e4a6SJamal Hadi Salim 			if (nhead > 0) {
2545a553e4a6SJamal Hadi Salim 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
2546a553e4a6SJamal Hadi Salim 				if (ret < 0) {
2547f9467eaeSJoe Perches 					pr_err("Error expanding ipsec packet %d\n",
2548f9467eaeSJoe Perches 					       ret);
2549b4bb4ac8SIlpo Järvinen 					goto err;
2550a553e4a6SJamal Hadi Salim 				}
2551a553e4a6SJamal Hadi Salim 			}
2552a553e4a6SJamal Hadi Salim 
2553a553e4a6SJamal Hadi Salim 			/* ipsec is not expecting ll header */
2554a553e4a6SJamal Hadi Salim 			skb_pull(skb, ETH_HLEN);
2555a553e4a6SJamal Hadi Salim 			ret = pktgen_output_ipsec(skb, pkt_dev);
2556a553e4a6SJamal Hadi Salim 			if (ret) {
2557f9467eaeSJoe Perches 				pr_err("Error creating ipsec packet %d\n", ret);
2558b4bb4ac8SIlpo Järvinen 				goto err;
2559a553e4a6SJamal Hadi Salim 			}
2560a553e4a6SJamal Hadi Salim 			/* restore ll */
2561a553e4a6SJamal Hadi Salim 			eth = (__u8 *) skb_push(skb, ETH_HLEN);
2562a553e4a6SJamal Hadi Salim 			memcpy(eth, pkt_dev->hh, 12);
2563a553e4a6SJamal Hadi Salim 			*(u16 *) &eth[12] = protocol;
2564a553e4a6SJamal Hadi Salim 		}
2565a553e4a6SJamal Hadi Salim 	}
2566a553e4a6SJamal Hadi Salim 	return 1;
2567b4bb4ac8SIlpo Järvinen err:
2568b4bb4ac8SIlpo Järvinen 	kfree_skb(skb);
2569b4bb4ac8SIlpo Järvinen 	return 0;
2570a553e4a6SJamal Hadi Salim }
2571a553e4a6SJamal Hadi Salim #endif
2572a553e4a6SJamal Hadi Salim 
2573ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
2574ca6549afSSteven Whitehouse {
2575ca6549afSSteven Whitehouse 	unsigned i;
257663adc6fbSStephen Hemminger 	for (i = 0; i < pkt_dev->nr_labels; i++)
2577ca6549afSSteven Whitehouse 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
257863adc6fbSStephen Hemminger 
2579ca6549afSSteven Whitehouse 	mpls--;
2580ca6549afSSteven Whitehouse 	*mpls |= MPLS_STACK_BOTTOM;
2581ca6549afSSteven Whitehouse }
2582ca6549afSSteven Whitehouse 
25830f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi,
25840f37c605SAl Viro 			       unsigned int prio)
25850f37c605SAl Viro {
25860f37c605SAl Viro 	return htons(id | (cfi << 12) | (prio << 13));
25870f37c605SAl Viro }
25880f37c605SAl Viro 
25891da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
25901da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
25911da177e4SLinus Torvalds {
25921da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
25931da177e4SLinus Torvalds 	__u8 *eth;
25941da177e4SLinus Torvalds 	struct udphdr *udph;
25951da177e4SLinus Torvalds 	int datalen, iplen;
25961da177e4SLinus Torvalds 	struct iphdr *iph;
25971da177e4SLinus Torvalds 	struct pktgen_hdr *pgh = NULL;
2598d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IP);
2599ca6549afSSteven Whitehouse 	__be32 *mpls;
260034954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
260134954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
260234954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
260334954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2604fd2ea0a7SDavid S. Miller 	u16 queue_map;
2605ca6549afSSteven Whitehouse 
2606ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2607d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
26081da177e4SLinus Torvalds 
260934954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2610d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
261134954ddcSFrancesco Fondelli 
261264053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
261364053beeSRobert Olsson 	 * fields.
261464053beeSRobert Olsson 	 */
2615fd2ea0a7SDavid S. Miller 	queue_map = pkt_dev->cur_queue_map;
261664053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
261764053beeSRobert Olsson 
26187ac5459eSDavid S. Miller 	datalen = (odev->hard_header_len + 16) & ~0xf;
2619e99b99b4SRobert Olsson 
2620e99b99b4SRobert Olsson 	if (pkt_dev->flags & F_NODE) {
2621e99b99b4SRobert Olsson 		int node;
2622e99b99b4SRobert Olsson 
2623e99b99b4SRobert Olsson 		if (pkt_dev->node >= 0)
2624e99b99b4SRobert Olsson 			node = pkt_dev->node;
2625e99b99b4SRobert Olsson 		else
2626e99b99b4SRobert Olsson 			node =  numa_node_id();
2627e99b99b4SRobert Olsson 
2628e99b99b4SRobert Olsson 		skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64
2629e99b99b4SRobert Olsson 				  + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node);
2630e99b99b4SRobert Olsson 		if (likely(skb)) {
2631e99b99b4SRobert Olsson 			skb_reserve(skb, NET_SKB_PAD);
2632e99b99b4SRobert Olsson 			skb->dev = odev;
2633e99b99b4SRobert Olsson 		}
2634e99b99b4SRobert Olsson 	}
2635e99b99b4SRobert Olsson 	else
2636e470757dSStephen Hemminger 	  skb = __netdev_alloc_skb(odev,
2637e470757dSStephen Hemminger 				   pkt_dev->cur_pkt_size + 64
2638e470757dSStephen Hemminger 				   + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
2639e99b99b4SRobert Olsson 
26401da177e4SLinus Torvalds 	if (!skb) {
26411da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
26421da177e4SLinus Torvalds 		return NULL;
26431da177e4SLinus Torvalds 	}
26441da177e4SLinus Torvalds 
26457ac5459eSDavid S. Miller 	skb_reserve(skb, datalen);
26461da177e4SLinus Torvalds 
26471da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
26481da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2649ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2650ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2651ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
265234954ddcSFrancesco Fondelli 
265334954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
265434954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
265534954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
26560f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
26570f37c605SAl Viro 					       pkt_dev->svlan_cfi,
26580f37c605SAl Viro 					       pkt_dev->svlan_p);
265934954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2660d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
266134954ddcSFrancesco Fondelli 		}
266234954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
26630f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
26640f37c605SAl Viro 				      pkt_dev->vlan_cfi,
26650f37c605SAl Viro 				      pkt_dev->vlan_p);
266634954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2667d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IP);
266834954ddcSFrancesco Fondelli 	}
266934954ddcSFrancesco Fondelli 
267027a884dcSArnaldo Carvalho de Melo 	skb->network_header = skb->tail;
2671b0e380b1SArnaldo Carvalho de Melo 	skb->transport_header = skb->network_header + sizeof(struct iphdr);
2672ddc7b8e3SArnaldo Carvalho de Melo 	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
2673fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
2674ddc7b8e3SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
2675ddc7b8e3SArnaldo Carvalho de Melo 	udph = udp_hdr(skb);
26761da177e4SLinus Torvalds 
26771da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2678252e3346SAl Viro 	*(__be16 *) & eth[12] = protocol;
26791da177e4SLinus Torvalds 
2680ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2681ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
268216dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
26831da177e4SLinus Torvalds 	if (datalen < sizeof(struct pktgen_hdr))
26841da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
26851da177e4SLinus Torvalds 
26861da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
26871da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
26881da177e4SLinus Torvalds 	udph->len = htons(datalen + 8);	/* DATA + udphdr */
26891da177e4SLinus Torvalds 	udph->check = 0;	/* No checksum */
26901da177e4SLinus Torvalds 
26911da177e4SLinus Torvalds 	iph->ihl = 5;
26921da177e4SLinus Torvalds 	iph->version = 4;
26931da177e4SLinus Torvalds 	iph->ttl = 32;
26941ca7768cSFrancesco Fondelli 	iph->tos = pkt_dev->tos;
26951da177e4SLinus Torvalds 	iph->protocol = IPPROTO_UDP;	/* UDP */
26961da177e4SLinus Torvalds 	iph->saddr = pkt_dev->cur_saddr;
26971da177e4SLinus Torvalds 	iph->daddr = pkt_dev->cur_daddr;
269866ed1e5eSEric Dumazet 	iph->id = htons(pkt_dev->ip_id);
269966ed1e5eSEric Dumazet 	pkt_dev->ip_id++;
27001da177e4SLinus Torvalds 	iph->frag_off = 0;
27011da177e4SLinus Torvalds 	iplen = 20 + 8 + datalen;
27021da177e4SLinus Torvalds 	iph->tot_len = htons(iplen);
27031da177e4SLinus Torvalds 	iph->check = 0;
27041da177e4SLinus Torvalds 	iph->check = ip_fast_csum((void *)iph, iph->ihl);
2705ca6549afSSteven Whitehouse 	skb->protocol = protocol;
2706b0e380b1SArnaldo Carvalho de Melo 	skb->mac_header = (skb->network_header - ETH_HLEN -
270716dab72fSJamal Hadi Salim 			   pkt_dev->pkt_overhead);
27081da177e4SLinus Torvalds 	skb->dev = odev;
27091da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
27101da177e4SLinus Torvalds 
271166ed1e5eSEric Dumazet 	if (pkt_dev->nfrags <= 0) {
27121da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
271366ed1e5eSEric Dumazet 		memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr));
271466ed1e5eSEric Dumazet 	} else {
27151da177e4SLinus Torvalds 		int frags = pkt_dev->nfrags;
271666ed1e5eSEric Dumazet 		int i, len;
27171da177e4SLinus Torvalds 
27181da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
27191da177e4SLinus Torvalds 
27201da177e4SLinus Torvalds 		if (frags > MAX_SKB_FRAGS)
27211da177e4SLinus Torvalds 			frags = MAX_SKB_FRAGS;
27221da177e4SLinus Torvalds 		if (datalen > frags * PAGE_SIZE) {
272366ed1e5eSEric Dumazet 			len = datalen - frags * PAGE_SIZE;
272466ed1e5eSEric Dumazet 			memset(skb_put(skb, len), 0, len);
27251da177e4SLinus Torvalds 			datalen = frags * PAGE_SIZE;
27261da177e4SLinus Torvalds 		}
27271da177e4SLinus Torvalds 
27281da177e4SLinus Torvalds 		i = 0;
27291da177e4SLinus Torvalds 		while (datalen > 0) {
273066ed1e5eSEric Dumazet 			struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
27311da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page = page;
27321da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page_offset = 0;
27331da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size =
27341da177e4SLinus Torvalds 			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
27351da177e4SLinus Torvalds 			datalen -= skb_shinfo(skb)->frags[i].size;
27361da177e4SLinus Torvalds 			skb->len += skb_shinfo(skb)->frags[i].size;
27371da177e4SLinus Torvalds 			skb->data_len += skb_shinfo(skb)->frags[i].size;
27381da177e4SLinus Torvalds 			i++;
27391da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
27401da177e4SLinus Torvalds 		}
27411da177e4SLinus Torvalds 
27421da177e4SLinus Torvalds 		while (i < frags) {
27431da177e4SLinus Torvalds 			int rem;
27441da177e4SLinus Torvalds 
27451da177e4SLinus Torvalds 			if (i == 0)
27461da177e4SLinus Torvalds 				break;
27471da177e4SLinus Torvalds 
27481da177e4SLinus Torvalds 			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
27491da177e4SLinus Torvalds 			if (rem == 0)
27501da177e4SLinus Torvalds 				break;
27511da177e4SLinus Torvalds 
27521da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i - 1].size -= rem;
27531da177e4SLinus Torvalds 
2754222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i] =
2755222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1];
27561da177e4SLinus Torvalds 			get_page(skb_shinfo(skb)->frags[i].page);
2757222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page =
2758222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].page;
2759222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page_offset +=
2760222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].size;
27611da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size = rem;
27621da177e4SLinus Torvalds 			i++;
27631da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
27641da177e4SLinus Torvalds 		}
27651da177e4SLinus Torvalds 	}
27661da177e4SLinus Torvalds 
276763adc6fbSStephen Hemminger 	/* Stamp the time, and sequence number,
276863adc6fbSStephen Hemminger 	 * convert them to network byte order
276963adc6fbSStephen Hemminger 	 */
27701da177e4SLinus Torvalds 	if (pgh) {
27711da177e4SLinus Torvalds 		struct timeval timestamp;
27721da177e4SLinus Torvalds 
27731da177e4SLinus Torvalds 		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
27741da177e4SLinus Torvalds 		pgh->seq_num = htonl(pkt_dev->seq_num);
27751da177e4SLinus Torvalds 
27761da177e4SLinus Torvalds 		do_gettimeofday(&timestamp);
27771da177e4SLinus Torvalds 		pgh->tv_sec = htonl(timestamp.tv_sec);
27781da177e4SLinus Torvalds 		pgh->tv_usec = htonl(timestamp.tv_usec);
27791da177e4SLinus Torvalds 	}
27801da177e4SLinus Torvalds 
2781a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2782a553e4a6SJamal Hadi Salim 	if (!process_ipsec(pkt_dev, skb, protocol))
2783a553e4a6SJamal Hadi Salim 		return NULL;
2784a553e4a6SJamal Hadi Salim #endif
2785a553e4a6SJamal Hadi Salim 
27861da177e4SLinus Torvalds 	return skb;
27871da177e4SLinus Torvalds }
27881da177e4SLinus Torvalds 
27891da177e4SLinus Torvalds /*
27901da177e4SLinus Torvalds  * scan_ip6, fmt_ip taken from dietlibc-0.21
27911da177e4SLinus Torvalds  * Author Felix von Leitner <felix-dietlibc@fefe.de>
27921da177e4SLinus Torvalds  *
27931da177e4SLinus Torvalds  * Slightly modified for kernel.
27941da177e4SLinus Torvalds  * Should be candidate for net/ipv4/utils.c
27951da177e4SLinus Torvalds  * --ro
27961da177e4SLinus Torvalds  */
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16])
27991da177e4SLinus Torvalds {
28001da177e4SLinus Torvalds 	unsigned int i;
28011da177e4SLinus Torvalds 	unsigned int len = 0;
28021da177e4SLinus Torvalds 	unsigned long u;
28031da177e4SLinus Torvalds 	char suffix[16];
28041da177e4SLinus Torvalds 	unsigned int prefixlen = 0;
28051da177e4SLinus Torvalds 	unsigned int suffixlen = 0;
2806252e3346SAl Viro 	__be32 tmp;
2807cfcabdccSStephen Hemminger 	char *pos;
28081da177e4SLinus Torvalds 
2809222f1806SLuiz Capitulino 	for (i = 0; i < 16; i++)
2810222f1806SLuiz Capitulino 		ip[i] = 0;
28111da177e4SLinus Torvalds 
28121da177e4SLinus Torvalds 	for (;;) {
28131da177e4SLinus Torvalds 		if (*s == ':') {
28141da177e4SLinus Torvalds 			len++;
28151da177e4SLinus Torvalds 			if (s[1] == ':') {	/* Found "::", skip to part 2 */
28161da177e4SLinus Torvalds 				s += 2;
28171da177e4SLinus Torvalds 				len++;
28181da177e4SLinus Torvalds 				break;
28191da177e4SLinus Torvalds 			}
28201da177e4SLinus Torvalds 			s++;
28211da177e4SLinus Torvalds 		}
28221da177e4SLinus Torvalds 
2823cfcabdccSStephen Hemminger 		u = simple_strtoul(s, &pos, 16);
2824cfcabdccSStephen Hemminger 		i = pos - s;
2825222f1806SLuiz Capitulino 		if (!i)
2826222f1806SLuiz Capitulino 			return 0;
28271da177e4SLinus Torvalds 		if (prefixlen == 12 && s[i] == '.') {
28281da177e4SLinus Torvalds 
28291da177e4SLinus Torvalds 			/* the last 4 bytes may be written as IPv4 address */
28301da177e4SLinus Torvalds 
28311da177e4SLinus Torvalds 			tmp = in_aton(s);
28321da177e4SLinus Torvalds 			memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
28331da177e4SLinus Torvalds 			return i + len;
28341da177e4SLinus Torvalds 		}
28351da177e4SLinus Torvalds 		ip[prefixlen++] = (u >> 8);
28361da177e4SLinus Torvalds 		ip[prefixlen++] = (u & 255);
2837222f1806SLuiz Capitulino 		s += i;
2838222f1806SLuiz Capitulino 		len += i;
28391da177e4SLinus Torvalds 		if (prefixlen == 16)
28401da177e4SLinus Torvalds 			return len;
28411da177e4SLinus Torvalds 	}
28421da177e4SLinus Torvalds 
28431da177e4SLinus Torvalds /* part 2, after "::" */
28441da177e4SLinus Torvalds 	for (;;) {
28451da177e4SLinus Torvalds 		if (*s == ':') {
28461da177e4SLinus Torvalds 			if (suffixlen == 0)
28471da177e4SLinus Torvalds 				break;
28481da177e4SLinus Torvalds 			s++;
28491da177e4SLinus Torvalds 			len++;
28501da177e4SLinus Torvalds 		} else if (suffixlen != 0)
28511da177e4SLinus Torvalds 			break;
2852cfcabdccSStephen Hemminger 
2853cfcabdccSStephen Hemminger 		u = simple_strtol(s, &pos, 16);
2854cfcabdccSStephen Hemminger 		i = pos - s;
28551da177e4SLinus Torvalds 		if (!i) {
2856222f1806SLuiz Capitulino 			if (*s)
2857222f1806SLuiz Capitulino 				len--;
28581da177e4SLinus Torvalds 			break;
28591da177e4SLinus Torvalds 		}
28601da177e4SLinus Torvalds 		if (suffixlen + prefixlen <= 12 && s[i] == '.') {
28611da177e4SLinus Torvalds 			tmp = in_aton(s);
2862222f1806SLuiz Capitulino 			memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
2863222f1806SLuiz Capitulino 			       sizeof(tmp));
28641da177e4SLinus Torvalds 			suffixlen += 4;
28651da177e4SLinus Torvalds 			len += strlen(s);
28661da177e4SLinus Torvalds 			break;
28671da177e4SLinus Torvalds 		}
28681da177e4SLinus Torvalds 		suffix[suffixlen++] = (u >> 8);
28691da177e4SLinus Torvalds 		suffix[suffixlen++] = (u & 255);
2870222f1806SLuiz Capitulino 		s += i;
2871222f1806SLuiz Capitulino 		len += i;
28721da177e4SLinus Torvalds 		if (prefixlen + suffixlen == 16)
28731da177e4SLinus Torvalds 			break;
28741da177e4SLinus Torvalds 	}
28751da177e4SLinus Torvalds 	for (i = 0; i < suffixlen; i++)
28761da177e4SLinus Torvalds 		ip[16 - suffixlen + i] = suffix[i];
28771da177e4SLinus Torvalds 	return len;
28781da177e4SLinus Torvalds }
28791da177e4SLinus Torvalds 
2880222f1806SLuiz Capitulino static char tohex(char hexdigit)
2881222f1806SLuiz Capitulino {
28821da177e4SLinus Torvalds 	return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
28831da177e4SLinus Torvalds }
28841da177e4SLinus Torvalds 
2885222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i)
2886222f1806SLuiz Capitulino {
28871da177e4SLinus Torvalds 	char *bak = s;
2888222f1806SLuiz Capitulino 	*s = tohex((i >> 12) & 0xf);
2889222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2890222f1806SLuiz Capitulino 		++s;
2891222f1806SLuiz Capitulino 	*s = tohex((i >> 8) & 0xf);
2892222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2893222f1806SLuiz Capitulino 		++s;
2894222f1806SLuiz Capitulino 	*s = tohex((i >> 4) & 0xf);
2895222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2896222f1806SLuiz Capitulino 		++s;
28971da177e4SLinus Torvalds 	*s = tohex(i & 0xf);
28981da177e4SLinus Torvalds 	return s - bak + 1;
28991da177e4SLinus Torvalds }
29001da177e4SLinus Torvalds 
2901222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16])
2902222f1806SLuiz Capitulino {
29031da177e4SLinus Torvalds 	unsigned int len;
29041da177e4SLinus Torvalds 	unsigned int i;
29051da177e4SLinus Torvalds 	unsigned int temp;
29061da177e4SLinus Torvalds 	unsigned int compressing;
29071da177e4SLinus Torvalds 	int j;
29081da177e4SLinus Torvalds 
2909222f1806SLuiz Capitulino 	len = 0;
2910222f1806SLuiz Capitulino 	compressing = 0;
29111da177e4SLinus Torvalds 	for (j = 0; j < 16; j += 2) {
29121da177e4SLinus Torvalds 
29131da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX
29141da177e4SLinus Torvalds 		if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
29151da177e4SLinus Torvalds 			inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
29161da177e4SLinus Torvalds 			temp = strlen(s);
29171da177e4SLinus Torvalds 			return len + temp;
29181da177e4SLinus Torvalds 		}
29191da177e4SLinus Torvalds #endif
29201da177e4SLinus Torvalds 		temp = ((unsigned long)(unsigned char)ip[j] << 8) +
29211da177e4SLinus Torvalds 		    (unsigned long)(unsigned char)ip[j + 1];
29221da177e4SLinus Torvalds 		if (temp == 0) {
29231da177e4SLinus Torvalds 			if (!compressing) {
29241da177e4SLinus Torvalds 				compressing = 1;
29251da177e4SLinus Torvalds 				if (j == 0) {
2926222f1806SLuiz Capitulino 					*s++ = ':';
2927222f1806SLuiz Capitulino 					++len;
29281da177e4SLinus Torvalds 				}
29291da177e4SLinus Torvalds 			}
29301da177e4SLinus Torvalds 		} else {
29311da177e4SLinus Torvalds 			if (compressing) {
29321da177e4SLinus Torvalds 				compressing = 0;
2933222f1806SLuiz Capitulino 				*s++ = ':';
2934222f1806SLuiz Capitulino 				++len;
29351da177e4SLinus Torvalds 			}
2936222f1806SLuiz Capitulino 			i = fmt_xlong(s, temp);
2937222f1806SLuiz Capitulino 			len += i;
2938222f1806SLuiz Capitulino 			s += i;
29391da177e4SLinus Torvalds 			if (j < 14) {
29401da177e4SLinus Torvalds 				*s++ = ':';
29411da177e4SLinus Torvalds 				++len;
29421da177e4SLinus Torvalds 			}
29431da177e4SLinus Torvalds 		}
29441da177e4SLinus Torvalds 	}
29451da177e4SLinus Torvalds 	if (compressing) {
2946222f1806SLuiz Capitulino 		*s++ = ':';
2947222f1806SLuiz Capitulino 		++len;
29481da177e4SLinus Torvalds 	}
29491da177e4SLinus Torvalds 	*s = 0;
29501da177e4SLinus Torvalds 	return len;
29511da177e4SLinus Torvalds }
29521da177e4SLinus Torvalds 
29531da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
29541da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
29551da177e4SLinus Torvalds {
29561da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
29571da177e4SLinus Torvalds 	__u8 *eth;
29581da177e4SLinus Torvalds 	struct udphdr *udph;
29591da177e4SLinus Torvalds 	int datalen;
29601da177e4SLinus Torvalds 	struct ipv6hdr *iph;
29611da177e4SLinus Torvalds 	struct pktgen_hdr *pgh = NULL;
2962d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IPV6);
2963ca6549afSSteven Whitehouse 	__be32 *mpls;
296434954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
296534954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
296634954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
296734954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2968fd2ea0a7SDavid S. Miller 	u16 queue_map;
2969ca6549afSSteven Whitehouse 
2970ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2971d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
29721da177e4SLinus Torvalds 
297334954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2974d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
297534954ddcSFrancesco Fondelli 
297664053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
297764053beeSRobert Olsson 	 * fields.
297864053beeSRobert Olsson 	 */
2979fd2ea0a7SDavid S. Miller 	queue_map = pkt_dev->cur_queue_map;
298064053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
298164053beeSRobert Olsson 
2982e470757dSStephen Hemminger 	skb = __netdev_alloc_skb(odev,
2983e470757dSStephen Hemminger 				 pkt_dev->cur_pkt_size + 64
2984e470757dSStephen Hemminger 				 + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT);
29851da177e4SLinus Torvalds 	if (!skb) {
29861da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
29871da177e4SLinus Torvalds 		return NULL;
29881da177e4SLinus Torvalds 	}
29891da177e4SLinus Torvalds 
29901da177e4SLinus Torvalds 	skb_reserve(skb, 16);
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
29931da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2994ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2995ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2996ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
299734954ddcSFrancesco Fondelli 
299834954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
299934954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
300034954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
30010f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
30020f37c605SAl Viro 					       pkt_dev->svlan_cfi,
30030f37c605SAl Viro 					       pkt_dev->svlan_p);
300434954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
3005d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
300634954ddcSFrancesco Fondelli 		}
300734954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
30080f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
30090f37c605SAl Viro 				      pkt_dev->vlan_cfi,
30100f37c605SAl Viro 				      pkt_dev->vlan_p);
301134954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
3012d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
301334954ddcSFrancesco Fondelli 	}
301434954ddcSFrancesco Fondelli 
301527a884dcSArnaldo Carvalho de Melo 	skb->network_header = skb->tail;
3016b0e380b1SArnaldo Carvalho de Melo 	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
3017ddc7b8e3SArnaldo Carvalho de Melo 	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
3018fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
3019ddc7b8e3SArnaldo Carvalho de Melo 	iph = ipv6_hdr(skb);
3020ddc7b8e3SArnaldo Carvalho de Melo 	udph = udp_hdr(skb);
30211da177e4SLinus Torvalds 
30221da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
3023252e3346SAl Viro 	*(__be16 *) &eth[12] = protocol;
30241da177e4SLinus Torvalds 
3025ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
3026ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 -
3027ca6549afSSteven Whitehouse 		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
302816dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
30291da177e4SLinus Torvalds 
30301da177e4SLinus Torvalds 	if (datalen < sizeof(struct pktgen_hdr)) {
30311da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
30321da177e4SLinus Torvalds 		if (net_ratelimit())
3033f9467eaeSJoe Perches 			pr_info("increased datalen to %d\n", datalen);
30341da177e4SLinus Torvalds 	}
30351da177e4SLinus Torvalds 
30361da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
30371da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
30381da177e4SLinus Torvalds 	udph->len = htons(datalen + sizeof(struct udphdr));
30391da177e4SLinus Torvalds 	udph->check = 0;	/* No checksum */
30401da177e4SLinus Torvalds 
3041d5f1ce9aSStephen Hemminger 	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
30421da177e4SLinus Torvalds 
30431ca7768cSFrancesco Fondelli 	if (pkt_dev->traffic_class) {
30441ca7768cSFrancesco Fondelli 		/* Version + traffic class + flow (0) */
3045252e3346SAl Viro 		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
30461ca7768cSFrancesco Fondelli 	}
30471ca7768cSFrancesco Fondelli 
30481da177e4SLinus Torvalds 	iph->hop_limit = 32;
30491da177e4SLinus Torvalds 
30501da177e4SLinus Torvalds 	iph->payload_len = htons(sizeof(struct udphdr) + datalen);
30511da177e4SLinus Torvalds 	iph->nexthdr = IPPROTO_UDP;
30521da177e4SLinus Torvalds 
30531da177e4SLinus Torvalds 	ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
30541da177e4SLinus Torvalds 	ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
30551da177e4SLinus Torvalds 
3056b0e380b1SArnaldo Carvalho de Melo 	skb->mac_header = (skb->network_header - ETH_HLEN -
305716dab72fSJamal Hadi Salim 			   pkt_dev->pkt_overhead);
3058ca6549afSSteven Whitehouse 	skb->protocol = protocol;
30591da177e4SLinus Torvalds 	skb->dev = odev;
30601da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
30611da177e4SLinus Torvalds 
30621da177e4SLinus Torvalds 	if (pkt_dev->nfrags <= 0)
30631da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
30641da177e4SLinus Torvalds 	else {
30651da177e4SLinus Torvalds 		int frags = pkt_dev->nfrags;
30661da177e4SLinus Torvalds 		int i;
30671da177e4SLinus Torvalds 
30681da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
30691da177e4SLinus Torvalds 
30701da177e4SLinus Torvalds 		if (frags > MAX_SKB_FRAGS)
30711da177e4SLinus Torvalds 			frags = MAX_SKB_FRAGS;
30721da177e4SLinus Torvalds 		if (datalen > frags * PAGE_SIZE) {
30731da177e4SLinus Torvalds 			skb_put(skb, datalen - frags * PAGE_SIZE);
30741da177e4SLinus Torvalds 			datalen = frags * PAGE_SIZE;
30751da177e4SLinus Torvalds 		}
30761da177e4SLinus Torvalds 
30771da177e4SLinus Torvalds 		i = 0;
30781da177e4SLinus Torvalds 		while (datalen > 0) {
30791da177e4SLinus Torvalds 			struct page *page = alloc_pages(GFP_KERNEL, 0);
30801da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page = page;
30811da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page_offset = 0;
30821da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size =
30831da177e4SLinus Torvalds 			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
30841da177e4SLinus Torvalds 			datalen -= skb_shinfo(skb)->frags[i].size;
30851da177e4SLinus Torvalds 			skb->len += skb_shinfo(skb)->frags[i].size;
30861da177e4SLinus Torvalds 			skb->data_len += skb_shinfo(skb)->frags[i].size;
30871da177e4SLinus Torvalds 			i++;
30881da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
30891da177e4SLinus Torvalds 		}
30901da177e4SLinus Torvalds 
30911da177e4SLinus Torvalds 		while (i < frags) {
30921da177e4SLinus Torvalds 			int rem;
30931da177e4SLinus Torvalds 
30941da177e4SLinus Torvalds 			if (i == 0)
30951da177e4SLinus Torvalds 				break;
30961da177e4SLinus Torvalds 
30971da177e4SLinus Torvalds 			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
30981da177e4SLinus Torvalds 			if (rem == 0)
30991da177e4SLinus Torvalds 				break;
31001da177e4SLinus Torvalds 
31011da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i - 1].size -= rem;
31021da177e4SLinus Torvalds 
3103222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i] =
3104222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1];
31051da177e4SLinus Torvalds 			get_page(skb_shinfo(skb)->frags[i].page);
3106222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page =
3107222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].page;
3108222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page_offset +=
3109222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].size;
31101da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size = rem;
31111da177e4SLinus Torvalds 			i++;
31121da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
31131da177e4SLinus Torvalds 		}
31141da177e4SLinus Torvalds 	}
31151da177e4SLinus Torvalds 
311663adc6fbSStephen Hemminger 	/* Stamp the time, and sequence number,
311763adc6fbSStephen Hemminger 	 * convert them to network byte order
311863adc6fbSStephen Hemminger 	 * should we update cloned packets too ?
311963adc6fbSStephen Hemminger 	 */
31201da177e4SLinus Torvalds 	if (pgh) {
31211da177e4SLinus Torvalds 		struct timeval timestamp;
31221da177e4SLinus Torvalds 
31231da177e4SLinus Torvalds 		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
31241da177e4SLinus Torvalds 		pgh->seq_num = htonl(pkt_dev->seq_num);
31251da177e4SLinus Torvalds 
31261da177e4SLinus Torvalds 		do_gettimeofday(&timestamp);
31271da177e4SLinus Torvalds 		pgh->tv_sec = htonl(timestamp.tv_sec);
31281da177e4SLinus Torvalds 		pgh->tv_usec = htonl(timestamp.tv_usec);
31291da177e4SLinus Torvalds 	}
313034954ddcSFrancesco Fondelli 	/* pkt_dev->seq_num++; FF: you really mean this? */
31311da177e4SLinus Torvalds 
31321da177e4SLinus Torvalds 	return skb;
31331da177e4SLinus Torvalds }
31341da177e4SLinus Torvalds 
3135475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev,
31361da177e4SLinus Torvalds 				   struct pktgen_dev *pkt_dev)
31371da177e4SLinus Torvalds {
31381da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
31391da177e4SLinus Torvalds 		return fill_packet_ipv6(odev, pkt_dev);
31401da177e4SLinus Torvalds 	else
31411da177e4SLinus Torvalds 		return fill_packet_ipv4(odev, pkt_dev);
31421da177e4SLinus Torvalds }
31431da177e4SLinus Torvalds 
31441da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
31451da177e4SLinus Torvalds {
31461da177e4SLinus Torvalds 	pkt_dev->seq_num = 1;
31471da177e4SLinus Torvalds 	pkt_dev->idle_acc = 0;
31481da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
31491da177e4SLinus Torvalds 	pkt_dev->tx_bytes = 0;
31501da177e4SLinus Torvalds 	pkt_dev->errors = 0;
31511da177e4SLinus Torvalds }
31521da177e4SLinus Torvalds 
31531da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */
31541da177e4SLinus Torvalds 
31551da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t)
31561da177e4SLinus Torvalds {
3157c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
31581da177e4SLinus Torvalds 	int started = 0;
31591da177e4SLinus Torvalds 
3160f9467eaeSJoe Perches 	func_enter();
31611da177e4SLinus Torvalds 
31621da177e4SLinus Torvalds 	if_lock(t);
3163c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
31641da177e4SLinus Torvalds 
31651da177e4SLinus Torvalds 		/*
31661da177e4SLinus Torvalds 		 * setup odev and create initial packet.
31671da177e4SLinus Torvalds 		 */
31681da177e4SLinus Torvalds 		pktgen_setup_inject(pkt_dev);
31691da177e4SLinus Torvalds 
31701da177e4SLinus Torvalds 		if (pkt_dev->odev) {
31711da177e4SLinus Torvalds 			pktgen_clear_counters(pkt_dev);
31721da177e4SLinus Torvalds 			pkt_dev->running = 1;	/* Cranke yeself! */
31731da177e4SLinus Torvalds 			pkt_dev->skb = NULL;
3174fd29cf72SStephen Hemminger 			pkt_dev->started_at =
3175fd29cf72SStephen Hemminger 				pkt_dev->next_tx = ktime_now();
3176fd29cf72SStephen Hemminger 
317716dab72fSJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
31781da177e4SLinus Torvalds 
31791da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Starting");
31801da177e4SLinus Torvalds 			started++;
3181222f1806SLuiz Capitulino 		} else
31821da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Error starting");
31831da177e4SLinus Torvalds 	}
31841da177e4SLinus Torvalds 	if_unlock(t);
3185222f1806SLuiz Capitulino 	if (started)
3186222f1806SLuiz Capitulino 		t->control &= ~(T_STOP);
31871da177e4SLinus Torvalds }
31881da177e4SLinus Torvalds 
31891da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void)
31901da177e4SLinus Torvalds {
3191cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31921da177e4SLinus Torvalds 
3193f9467eaeSJoe Perches 	func_enter();
31941da177e4SLinus Torvalds 
31956146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3196cdcdbe0bSLuiz Capitulino 
3197cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list)
319895ed63f7SArthur Kepner 		t->control |= T_STOP;
3199cdcdbe0bSLuiz Capitulino 
32006146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32011da177e4SLinus Torvalds }
32021da177e4SLinus Torvalds 
3203648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t)
32041da177e4SLinus Torvalds {
3205648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
32061da177e4SLinus Torvalds 
3207c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
3208648fda74SStephen Hemminger 		if (pkt_dev->running)
3209648fda74SStephen Hemminger 			return 1;
3210648fda74SStephen Hemminger 	return 0;
32111da177e4SLinus Torvalds }
32121da177e4SLinus Torvalds 
32131da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t)
32141da177e4SLinus Torvalds {
32151da177e4SLinus Torvalds 	if_lock(t);
32161da177e4SLinus Torvalds 
32171da177e4SLinus Torvalds 	while (thread_is_running(t)) {
32181da177e4SLinus Torvalds 
32191da177e4SLinus Torvalds 		if_unlock(t);
32201da177e4SLinus Torvalds 
32211da177e4SLinus Torvalds 		msleep_interruptible(100);
32221da177e4SLinus Torvalds 
32231da177e4SLinus Torvalds 		if (signal_pending(current))
32241da177e4SLinus Torvalds 			goto signal;
32251da177e4SLinus Torvalds 		if_lock(t);
32261da177e4SLinus Torvalds 	}
32271da177e4SLinus Torvalds 	if_unlock(t);
32281da177e4SLinus Torvalds 	return 1;
32291da177e4SLinus Torvalds signal:
32301da177e4SLinus Torvalds 	return 0;
32311da177e4SLinus Torvalds }
32321da177e4SLinus Torvalds 
32331da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void)
32341da177e4SLinus Torvalds {
3235cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
32361da177e4SLinus Torvalds 	int sig = 1;
32371da177e4SLinus Torvalds 
32386146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3239cdcdbe0bSLuiz Capitulino 
3240cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list) {
32411da177e4SLinus Torvalds 		sig = pktgen_wait_thread_run(t);
3242222f1806SLuiz Capitulino 		if (sig == 0)
3243222f1806SLuiz Capitulino 			break;
32441da177e4SLinus Torvalds 	}
3245cdcdbe0bSLuiz Capitulino 
3246cdcdbe0bSLuiz Capitulino 	if (sig == 0)
3247cdcdbe0bSLuiz Capitulino 		list_for_each_entry(t, &pktgen_threads, th_list)
32481da177e4SLinus Torvalds 			t->control |= (T_STOP);
3249cdcdbe0bSLuiz Capitulino 
32506146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32511da177e4SLinus Torvalds 	return sig;
32521da177e4SLinus Torvalds }
32531da177e4SLinus Torvalds 
32541da177e4SLinus Torvalds static void pktgen_run_all_threads(void)
32551da177e4SLinus Torvalds {
3256cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
32571da177e4SLinus Torvalds 
3258f9467eaeSJoe Perches 	func_enter();
32591da177e4SLinus Torvalds 
32606146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
32611da177e4SLinus Torvalds 
3262cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list)
32631da177e4SLinus Torvalds 		t->control |= (T_RUN);
3264cdcdbe0bSLuiz Capitulino 
32656146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32661da177e4SLinus Torvalds 
326763adc6fbSStephen Hemminger 	/* Propagate thread->control  */
326863adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
32691da177e4SLinus Torvalds 
32701da177e4SLinus Torvalds 	pktgen_wait_all_threads_run();
32711da177e4SLinus Torvalds }
32721da177e4SLinus Torvalds 
3273eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void)
3274eb37b41cSJesse Brandeburg {
3275eb37b41cSJesse Brandeburg 	struct pktgen_thread *t;
3276eb37b41cSJesse Brandeburg 
3277f9467eaeSJoe Perches 	func_enter();
3278eb37b41cSJesse Brandeburg 
3279eb37b41cSJesse Brandeburg 	mutex_lock(&pktgen_thread_lock);
3280eb37b41cSJesse Brandeburg 
3281eb37b41cSJesse Brandeburg 	list_for_each_entry(t, &pktgen_threads, th_list)
3282eb37b41cSJesse Brandeburg 		t->control |= (T_REMDEVALL);
3283eb37b41cSJesse Brandeburg 
3284eb37b41cSJesse Brandeburg 	mutex_unlock(&pktgen_thread_lock);
3285eb37b41cSJesse Brandeburg 
328663adc6fbSStephen Hemminger 	/* Propagate thread->control  */
328763adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
3288eb37b41cSJesse Brandeburg 
3289eb37b41cSJesse Brandeburg 	pktgen_wait_all_threads_run();
3290eb37b41cSJesse Brandeburg }
3291eb37b41cSJesse Brandeburg 
32921da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
32931da177e4SLinus Torvalds {
3294fd29cf72SStephen Hemminger 	__u64 bps, mbps, pps;
32951da177e4SLinus Torvalds 	char *p = pkt_dev->result;
3296fd29cf72SStephen Hemminger 	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
3297fd29cf72SStephen Hemminger 				    pkt_dev->started_at);
3298fd29cf72SStephen Hemminger 	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
32991da177e4SLinus Torvalds 
3300fd29cf72SStephen Hemminger 	p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
3301fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(elapsed),
3302fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
3303fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(idle),
33041da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->sofar,
33051da177e4SLinus Torvalds 		     pkt_dev->cur_pkt_size, nr_frags);
33061da177e4SLinus Torvalds 
3307fd29cf72SStephen Hemminger 	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
3308fd29cf72SStephen Hemminger 			ktime_to_ns(elapsed));
33091da177e4SLinus Torvalds 
33101da177e4SLinus Torvalds 	bps = pps * 8 * pkt_dev->cur_pkt_size;
33111da177e4SLinus Torvalds 
33121da177e4SLinus Torvalds 	mbps = bps;
33131da177e4SLinus Torvalds 	do_div(mbps, 1000000);
33141da177e4SLinus Torvalds 	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
33151da177e4SLinus Torvalds 		     (unsigned long long)pps,
33161da177e4SLinus Torvalds 		     (unsigned long long)mbps,
33171da177e4SLinus Torvalds 		     (unsigned long long)bps,
33181da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->errors);
33191da177e4SLinus Torvalds }
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */
33221da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
33231da177e4SLinus Torvalds {
3324222f1806SLuiz Capitulino 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
33251da177e4SLinus Torvalds 
33261da177e4SLinus Torvalds 	if (!pkt_dev->running) {
3327f9467eaeSJoe Perches 		pr_warning("interface: %s is already stopped\n",
3328f9467eaeSJoe Perches 			   pkt_dev->odevname);
33291da177e4SLinus Torvalds 		return -EINVAL;
33301da177e4SLinus Torvalds 	}
33311da177e4SLinus Torvalds 
33323bda06a3SStephen Hemminger 	kfree_skb(pkt_dev->skb);
33333bda06a3SStephen Hemminger 	pkt_dev->skb = NULL;
3334fd29cf72SStephen Hemminger 	pkt_dev->stopped_at = ktime_now();
33351da177e4SLinus Torvalds 	pkt_dev->running = 0;
33361da177e4SLinus Torvalds 
333795ed63f7SArthur Kepner 	show_results(pkt_dev, nr_frags);
33381da177e4SLinus Torvalds 
33391da177e4SLinus Torvalds 	return 0;
33401da177e4SLinus Torvalds }
33411da177e4SLinus Torvalds 
33421da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
33431da177e4SLinus Torvalds {
3344c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev, *best = NULL;
33451da177e4SLinus Torvalds 
33461da177e4SLinus Torvalds 	if_lock(t);
33471da177e4SLinus Torvalds 
3348c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
3349c26a8016SLuiz Capitulino 		if (!pkt_dev->running)
3350222f1806SLuiz Capitulino 			continue;
3351222f1806SLuiz Capitulino 		if (best == NULL)
3352c26a8016SLuiz Capitulino 			best = pkt_dev;
3353fd29cf72SStephen Hemminger 		else if (ktime_lt(pkt_dev->next_tx, best->next_tx))
3354c26a8016SLuiz Capitulino 			best = pkt_dev;
33551da177e4SLinus Torvalds 	}
33561da177e4SLinus Torvalds 	if_unlock(t);
33571da177e4SLinus Torvalds 	return best;
33581da177e4SLinus Torvalds }
33591da177e4SLinus Torvalds 
3360222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t)
3361222f1806SLuiz Capitulino {
3362c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
33631da177e4SLinus Torvalds 
3364f9467eaeSJoe Perches 	func_enter();
33651da177e4SLinus Torvalds 
33661da177e4SLinus Torvalds 	if_lock(t);
33671da177e4SLinus Torvalds 
3368c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
3369c26a8016SLuiz Capitulino 		pktgen_stop_device(pkt_dev);
337095ed63f7SArthur Kepner 	}
337195ed63f7SArthur Kepner 
337295ed63f7SArthur Kepner 	if_unlock(t);
337395ed63f7SArthur Kepner }
337495ed63f7SArthur Kepner 
337595ed63f7SArthur Kepner /*
337695ed63f7SArthur Kepner  * one of our devices needs to be removed - find it
337795ed63f7SArthur Kepner  * and remove it
337895ed63f7SArthur Kepner  */
337995ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t)
338095ed63f7SArthur Kepner {
3381c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3382c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
338395ed63f7SArthur Kepner 
3384f9467eaeSJoe Perches 	func_enter();
338595ed63f7SArthur Kepner 
338695ed63f7SArthur Kepner 	if_lock(t);
338795ed63f7SArthur Kepner 
3388c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3389c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
339095ed63f7SArthur Kepner 
3391222f1806SLuiz Capitulino 		if (!cur->removal_mark)
3392222f1806SLuiz Capitulino 			continue;
339395ed63f7SArthur Kepner 
339495ed63f7SArthur Kepner 		kfree_skb(cur->skb);
339595ed63f7SArthur Kepner 		cur->skb = NULL;
339695ed63f7SArthur Kepner 
339795ed63f7SArthur Kepner 		pktgen_remove_device(t, cur);
339895ed63f7SArthur Kepner 
339995ed63f7SArthur Kepner 		break;
340095ed63f7SArthur Kepner 	}
34011da177e4SLinus Torvalds 
34021da177e4SLinus Torvalds 	if_unlock(t);
34031da177e4SLinus Torvalds }
34041da177e4SLinus Torvalds 
34051da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t)
34061da177e4SLinus Torvalds {
3407c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3408c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
34091da177e4SLinus Torvalds 
3410f9467eaeSJoe Perches 	func_enter();
3411f9467eaeSJoe Perches 
34121da177e4SLinus Torvalds 	/* Remove all devices, free mem */
34131da177e4SLinus Torvalds 
34141da177e4SLinus Torvalds 	if_lock(t);
34151da177e4SLinus Torvalds 
3416c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3417c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
341895ed63f7SArthur Kepner 
341995ed63f7SArthur Kepner 		kfree_skb(cur->skb);
342095ed63f7SArthur Kepner 		cur->skb = NULL;
342195ed63f7SArthur Kepner 
34221da177e4SLinus Torvalds 		pktgen_remove_device(t, cur);
34231da177e4SLinus Torvalds 	}
34241da177e4SLinus Torvalds 
34251da177e4SLinus Torvalds 	if_unlock(t);
34261da177e4SLinus Torvalds }
34271da177e4SLinus Torvalds 
34281da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t)
34291da177e4SLinus Torvalds {
34301da177e4SLinus Torvalds 	/* Remove from the thread list */
34311da177e4SLinus Torvalds 
3432ee74baa7SDavid S. Miller 	remove_proc_entry(t->tsk->comm, pg_proc_dir);
34331da177e4SLinus Torvalds 
34346146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
34351da177e4SLinus Torvalds 
3436cdcdbe0bSLuiz Capitulino 	list_del(&t->th_list);
3437cdcdbe0bSLuiz Capitulino 
34386146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
34391da177e4SLinus Torvalds }
34401da177e4SLinus Torvalds 
3441ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev)
34423791decbSStephen Hemminger {
3443fd29cf72SStephen Hemminger 	ktime_t idle_start = ktime_now();
34443791decbSStephen Hemminger 	schedule();
3445fd29cf72SStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
34463791decbSStephen Hemminger }
34473791decbSStephen Hemminger 
3448ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
3449ef87979cSStephen Hemminger {
3450ef87979cSStephen Hemminger 	ktime_t idle_start = ktime_now();
3451ef87979cSStephen Hemminger 
3452ef87979cSStephen Hemminger 	while (atomic_read(&(pkt_dev->skb->users)) != 1) {
3453ef87979cSStephen Hemminger 		if (signal_pending(current))
3454ef87979cSStephen Hemminger 			break;
3455ef87979cSStephen Hemminger 
3456ef87979cSStephen Hemminger 		if (need_resched())
3457ef87979cSStephen Hemminger 			pktgen_resched(pkt_dev);
3458ef87979cSStephen Hemminger 		else
3459ef87979cSStephen Hemminger 			cpu_relax();
3460ef87979cSStephen Hemminger 	}
3461ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
3462ef87979cSStephen Hemminger }
3463fd29cf72SStephen Hemminger 
3464475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev)
34651da177e4SLinus Torvalds {
346600829823SStephen Hemminger 	struct net_device *odev = pkt_dev->odev;
34676fef4c0cSStephen Hemminger 	netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *)
346800829823SStephen Hemminger 		= odev->netdev_ops->ndo_start_xmit;
3469fd2ea0a7SDavid S. Miller 	struct netdev_queue *txq;
3470fd2ea0a7SDavid S. Miller 	u16 queue_map;
34711da177e4SLinus Torvalds 	int ret;
34721da177e4SLinus Torvalds 
3473ef87979cSStephen Hemminger 	/* If device is offline, then don't send */
3474ef87979cSStephen Hemminger 	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
34751da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
34763791decbSStephen Hemminger 		return;
34771da177e4SLinus Torvalds 	}
34781da177e4SLinus Torvalds 
3479ef87979cSStephen Hemminger 	/* This is max DELAY, this has special meaning of
3480ef87979cSStephen Hemminger 	 * "never transmit"
3481ef87979cSStephen Hemminger 	 */
3482ef87979cSStephen Hemminger 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3483ef87979cSStephen Hemminger 		pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX);
3484ef87979cSStephen Hemminger 		return;
3485ef87979cSStephen Hemminger 	}
3486ef87979cSStephen Hemminger 
3487ef87979cSStephen Hemminger 	/* If no skb or clone count exhausted then get new one */
34887d7bb1cfSStephen Hemminger 	if (!pkt_dev->skb || (pkt_dev->last_ok &&
34897d7bb1cfSStephen Hemminger 			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
34901da177e4SLinus Torvalds 		/* build a new pkt */
34911da177e4SLinus Torvalds 		kfree_skb(pkt_dev->skb);
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 		pkt_dev->skb = fill_packet(odev, pkt_dev);
34941da177e4SLinus Torvalds 		if (pkt_dev->skb == NULL) {
3495f9467eaeSJoe Perches 			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
34961da177e4SLinus Torvalds 			schedule();
34971da177e4SLinus Torvalds 			pkt_dev->clone_count--;	/* back out increment, OOM */
34983791decbSStephen Hemminger 			return;
34991da177e4SLinus Torvalds 		}
3500baac8564SEric Dumazet 		pkt_dev->last_pkt_size = pkt_dev->skb->len;
35011da177e4SLinus Torvalds 		pkt_dev->allocated_skbs++;
35021da177e4SLinus Torvalds 		pkt_dev->clone_count = 0;	/* reset counter */
35031da177e4SLinus Torvalds 	}
35041da177e4SLinus Torvalds 
3505ef87979cSStephen Hemminger 	if (pkt_dev->delay && pkt_dev->last_ok)
3506ef87979cSStephen Hemminger 		spin(pkt_dev, pkt_dev->next_tx);
3507ef87979cSStephen Hemminger 
3508fd2ea0a7SDavid S. Miller 	queue_map = skb_get_queue_mapping(pkt_dev->skb);
3509fd2ea0a7SDavid S. Miller 	txq = netdev_get_tx_queue(odev, queue_map);
3510fd2ea0a7SDavid S. Miller 
3511fd2ea0a7SDavid S. Miller 	__netif_tx_lock_bh(txq);
35125b8db2f5SStephen Hemminger 
35130835acfeSEric Dumazet 	if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) {
3514ef87979cSStephen Hemminger 		ret = NETDEV_TX_BUSY;
35150835acfeSEric Dumazet 		pkt_dev->last_ok = 0;
35160835acfeSEric Dumazet 		goto unlock;
35170835acfeSEric Dumazet 	}
35180835acfeSEric Dumazet 	atomic_inc(&(pkt_dev->skb->users));
351900829823SStephen Hemminger 	ret = (*xmit)(pkt_dev->skb, odev);
3520ef87979cSStephen Hemminger 
35215b8db2f5SStephen Hemminger 	switch (ret) {
35225b8db2f5SStephen Hemminger 	case NETDEV_TX_OK:
352308baf561SEric Dumazet 		txq_trans_update(txq);
35241da177e4SLinus Torvalds 		pkt_dev->last_ok = 1;
35251da177e4SLinus Torvalds 		pkt_dev->sofar++;
35261da177e4SLinus Torvalds 		pkt_dev->seq_num++;
3527baac8564SEric Dumazet 		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
35285b8db2f5SStephen Hemminger 		break;
3529f466dba1SJohn Fastabend 	case NET_XMIT_DROP:
3530f466dba1SJohn Fastabend 	case NET_XMIT_CN:
3531f466dba1SJohn Fastabend 	case NET_XMIT_POLICED:
3532f466dba1SJohn Fastabend 		/* skb has been consumed */
3533f466dba1SJohn Fastabend 		pkt_dev->errors++;
3534f466dba1SJohn Fastabend 		break;
35355b8db2f5SStephen Hemminger 	default: /* Drivers are not supposed to return other values! */
35365b8db2f5SStephen Hemminger 		if (net_ratelimit())
35375b8db2f5SStephen Hemminger 			pr_info("pktgen: %s xmit error: %d\n",
3538593f63b0SEric Dumazet 				pkt_dev->odevname, ret);
35391da177e4SLinus Torvalds 		pkt_dev->errors++;
35405b8db2f5SStephen Hemminger 		/* fallthru */
3541ef87979cSStephen Hemminger 	case NETDEV_TX_LOCKED:
35425b8db2f5SStephen Hemminger 	case NETDEV_TX_BUSY:
35435b8db2f5SStephen Hemminger 		/* Retry it next time */
35445b8db2f5SStephen Hemminger 		atomic_dec(&(pkt_dev->skb->users));
35451da177e4SLinus Torvalds 		pkt_dev->last_ok = 0;
35461da177e4SLinus Torvalds 	}
35470835acfeSEric Dumazet unlock:
3548fd2ea0a7SDavid S. Miller 	__netif_tx_unlock_bh(txq);
35491da177e4SLinus Torvalds 
35501da177e4SLinus Torvalds 	/* If pkt_dev->count is zero, then run forever */
35511da177e4SLinus Torvalds 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
3552ef87979cSStephen Hemminger 		pktgen_wait_for_skb(pkt_dev);
35531da177e4SLinus Torvalds 
35541da177e4SLinus Torvalds 		/* Done with this */
35551da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
35561da177e4SLinus Torvalds 	}
35571da177e4SLinus Torvalds }
35581da177e4SLinus Torvalds 
35591da177e4SLinus Torvalds /*
35601da177e4SLinus Torvalds  * Main loop of the thread goes here
35611da177e4SLinus Torvalds  */
35621da177e4SLinus Torvalds 
3563ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg)
35641da177e4SLinus Torvalds {
35651da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
3566ee74baa7SDavid S. Miller 	struct pktgen_thread *t = arg;
35671da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
35681da177e4SLinus Torvalds 	int cpu = t->cpu;
35691da177e4SLinus Torvalds 
3570ee74baa7SDavid S. Miller 	BUG_ON(smp_processor_id() != cpu);
35711da177e4SLinus Torvalds 
35721da177e4SLinus Torvalds 	init_waitqueue_head(&t->queue);
3573d3ede327SDenis V. Lunev 	complete(&t->start_done);
35741da177e4SLinus Torvalds 
3575f9467eaeSJoe Perches 	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
35761da177e4SLinus Torvalds 
3577ee74baa7SDavid S. Miller 	set_current_state(TASK_INTERRUPTIBLE);
35781da177e4SLinus Torvalds 
357983144186SRafael J. Wysocki 	set_freezable();
358083144186SRafael J. Wysocki 
3581ee74baa7SDavid S. Miller 	while (!kthread_should_stop()) {
3582ee74baa7SDavid S. Miller 		pkt_dev = next_to_run(t);
3583ee74baa7SDavid S. Miller 
3584ef87979cSStephen Hemminger 		if (unlikely(!pkt_dev && t->control == 0)) {
3585ef87979cSStephen Hemminger 			wait_event_interruptible_timeout(t->queue,
3586ef87979cSStephen Hemminger 							 t->control != 0,
3587ef87979cSStephen Hemminger 							 HZ/10);
35881b3f720bSRafael J. Wysocki 			try_to_freeze();
3589ef87979cSStephen Hemminger 			continue;
3590ee74baa7SDavid S. Miller 		}
35911da177e4SLinus Torvalds 
35921da177e4SLinus Torvalds 		__set_current_state(TASK_RUNNING);
35931da177e4SLinus Torvalds 
3594ef87979cSStephen Hemminger 		if (likely(pkt_dev)) {
35951da177e4SLinus Torvalds 			pktgen_xmit(pkt_dev);
35961da177e4SLinus Torvalds 
3597ef87979cSStephen Hemminger 			if (need_resched())
3598ef87979cSStephen Hemminger 				pktgen_resched(pkt_dev);
3599ef87979cSStephen Hemminger 			else
3600ef87979cSStephen Hemminger 				cpu_relax();
3601ef87979cSStephen Hemminger 		}
3602ef87979cSStephen Hemminger 
36031da177e4SLinus Torvalds 		if (t->control & T_STOP) {
36041da177e4SLinus Torvalds 			pktgen_stop(t);
36051da177e4SLinus Torvalds 			t->control &= ~(T_STOP);
36061da177e4SLinus Torvalds 		}
36071da177e4SLinus Torvalds 
36081da177e4SLinus Torvalds 		if (t->control & T_RUN) {
36091da177e4SLinus Torvalds 			pktgen_run(t);
36101da177e4SLinus Torvalds 			t->control &= ~(T_RUN);
36111da177e4SLinus Torvalds 		}
36121da177e4SLinus Torvalds 
361395ed63f7SArthur Kepner 		if (t->control & T_REMDEVALL) {
36141da177e4SLinus Torvalds 			pktgen_rem_all_ifs(t);
361595ed63f7SArthur Kepner 			t->control &= ~(T_REMDEVALL);
361695ed63f7SArthur Kepner 		}
361795ed63f7SArthur Kepner 
361895ed63f7SArthur Kepner 		if (t->control & T_REMDEV) {
361995ed63f7SArthur Kepner 			pktgen_rem_one_if(t);
36201da177e4SLinus Torvalds 			t->control &= ~(T_REMDEV);
36211da177e4SLinus Torvalds 		}
36221da177e4SLinus Torvalds 
362309fe3ef4SAndrew Morton 		try_to_freeze();
362409fe3ef4SAndrew Morton 
3625ee74baa7SDavid S. Miller 		set_current_state(TASK_INTERRUPTIBLE);
36261da177e4SLinus Torvalds 	}
36271da177e4SLinus Torvalds 
3628f9467eaeSJoe Perches 	pr_debug("%s stopping all device\n", t->tsk->comm);
36291da177e4SLinus Torvalds 	pktgen_stop(t);
36301da177e4SLinus Torvalds 
3631f9467eaeSJoe Perches 	pr_debug("%s removing all device\n", t->tsk->comm);
36321da177e4SLinus Torvalds 	pktgen_rem_all_ifs(t);
36331da177e4SLinus Torvalds 
3634f9467eaeSJoe Perches 	pr_debug("%s removing thread\n", t->tsk->comm);
36351da177e4SLinus Torvalds 	pktgen_rem_thread(t);
3636cdcdbe0bSLuiz Capitulino 
3637ee74baa7SDavid S. Miller 	return 0;
36381da177e4SLinus Torvalds }
36391da177e4SLinus Torvalds 
3640222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
36413e984840SEric Dumazet 					  const char *ifname, bool exact)
36421da177e4SLinus Torvalds {
3643c26a8016SLuiz Capitulino 	struct pktgen_dev *p, *pkt_dev = NULL;
36443e984840SEric Dumazet 	size_t len = strlen(ifname);
36451da177e4SLinus Torvalds 
36463e984840SEric Dumazet 	if_lock(t);
3647c26a8016SLuiz Capitulino 	list_for_each_entry(p, &t->if_list, list)
36483e984840SEric Dumazet 		if (strncmp(p->odevname, ifname, len) == 0) {
36493e984840SEric Dumazet 			if (p->odevname[len]) {
36503e984840SEric Dumazet 				if (exact || p->odevname[len] != '@')
36513e984840SEric Dumazet 					continue;
36523e984840SEric Dumazet 			}
3653c26a8016SLuiz Capitulino 			pkt_dev = p;
36541da177e4SLinus Torvalds 			break;
36551da177e4SLinus Torvalds 		}
36561da177e4SLinus Torvalds 
36571da177e4SLinus Torvalds 	if_unlock(t);
3658f9467eaeSJoe Perches 	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
36591da177e4SLinus Torvalds 	return pkt_dev;
36601da177e4SLinus Torvalds }
36611da177e4SLinus Torvalds 
36621da177e4SLinus Torvalds /*
36631da177e4SLinus Torvalds  * Adds a dev at front of if_list.
36641da177e4SLinus Torvalds  */
36651da177e4SLinus Torvalds 
3666222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t,
3667222f1806SLuiz Capitulino 			     struct pktgen_dev *pkt_dev)
36681da177e4SLinus Torvalds {
36691da177e4SLinus Torvalds 	int rv = 0;
36701da177e4SLinus Torvalds 
36711da177e4SLinus Torvalds 	if_lock(t);
36721da177e4SLinus Torvalds 
36731da177e4SLinus Torvalds 	if (pkt_dev->pg_thread) {
3674f9467eaeSJoe Perches 		pr_err("ERROR: already assigned to a thread\n");
36751da177e4SLinus Torvalds 		rv = -EBUSY;
36761da177e4SLinus Torvalds 		goto out;
36771da177e4SLinus Torvalds 	}
3678c26a8016SLuiz Capitulino 
3679c26a8016SLuiz Capitulino 	list_add(&pkt_dev->list, &t->if_list);
36801da177e4SLinus Torvalds 	pkt_dev->pg_thread = t;
36811da177e4SLinus Torvalds 	pkt_dev->running = 0;
36821da177e4SLinus Torvalds 
36831da177e4SLinus Torvalds out:
36841da177e4SLinus Torvalds 	if_unlock(t);
36851da177e4SLinus Torvalds 	return rv;
36861da177e4SLinus Torvalds }
36871da177e4SLinus Torvalds 
36881da177e4SLinus Torvalds /* Called under thread lock */
36891da177e4SLinus Torvalds 
36901da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
36911da177e4SLinus Torvalds {
36921da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev;
369339df232fSStephen Hemminger 	int err;
36943291b9dbSEric Dumazet 	int node = cpu_to_node(t->cpu);
36951da177e4SLinus Torvalds 
36961da177e4SLinus Torvalds 	/* We don't allow a device to be on several threads */
36971da177e4SLinus Torvalds 
3698d50a6b56SStephen Hemminger 	pkt_dev = __pktgen_NN_threads(ifname, FIND);
3699d50a6b56SStephen Hemminger 	if (pkt_dev) {
3700f9467eaeSJoe Perches 		pr_err("ERROR: interface already used\n");
3701d50a6b56SStephen Hemminger 		return -EBUSY;
3702d50a6b56SStephen Hemminger 	}
37031da177e4SLinus Torvalds 
37043291b9dbSEric Dumazet 	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
37051da177e4SLinus Torvalds 	if (!pkt_dev)
37061da177e4SLinus Torvalds 		return -ENOMEM;
37071da177e4SLinus Torvalds 
3708593f63b0SEric Dumazet 	strcpy(pkt_dev->odevname, ifname);
37093291b9dbSEric Dumazet 	pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state),
37103291b9dbSEric Dumazet 				      node);
37111da177e4SLinus Torvalds 	if (pkt_dev->flows == NULL) {
37121da177e4SLinus Torvalds 		kfree(pkt_dev);
37131da177e4SLinus Torvalds 		return -ENOMEM;
37141da177e4SLinus Torvalds 	}
37151da177e4SLinus Torvalds 	memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state));
37161da177e4SLinus Torvalds 
371795ed63f7SArthur Kepner 	pkt_dev->removal_mark = 0;
37181da177e4SLinus Torvalds 	pkt_dev->min_pkt_size = ETH_ZLEN;
37191da177e4SLinus Torvalds 	pkt_dev->max_pkt_size = ETH_ZLEN;
37201da177e4SLinus Torvalds 	pkt_dev->nfrags = 0;
37211da177e4SLinus Torvalds 	pkt_dev->clone_skb = pg_clone_skb_d;
3722fd29cf72SStephen Hemminger 	pkt_dev->delay = pg_delay_d;
37231da177e4SLinus Torvalds 	pkt_dev->count = pg_count_d;
37241da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
37251da177e4SLinus Torvalds 	pkt_dev->udp_src_min = 9;	/* sink port */
37261da177e4SLinus Torvalds 	pkt_dev->udp_src_max = 9;
37271da177e4SLinus Torvalds 	pkt_dev->udp_dst_min = 9;
37281da177e4SLinus Torvalds 	pkt_dev->udp_dst_max = 9;
37291da177e4SLinus Torvalds 
373034954ddcSFrancesco Fondelli 	pkt_dev->vlan_p = 0;
373134954ddcSFrancesco Fondelli 	pkt_dev->vlan_cfi = 0;
373234954ddcSFrancesco Fondelli 	pkt_dev->vlan_id = 0xffff;
373334954ddcSFrancesco Fondelli 	pkt_dev->svlan_p = 0;
373434954ddcSFrancesco Fondelli 	pkt_dev->svlan_cfi = 0;
373534954ddcSFrancesco Fondelli 	pkt_dev->svlan_id = 0xffff;
3736e99b99b4SRobert Olsson 	pkt_dev->node = -1;
373734954ddcSFrancesco Fondelli 
373839df232fSStephen Hemminger 	err = pktgen_setup_dev(pkt_dev, ifname);
373939df232fSStephen Hemminger 	if (err)
374039df232fSStephen Hemminger 		goto out1;
37411da177e4SLinus Torvalds 
37425efdccbcSDenis V. Lunev 	pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
37435efdccbcSDenis V. Lunev 					  &pktgen_if_fops, pkt_dev);
374439df232fSStephen Hemminger 	if (!pkt_dev->entry) {
3745f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3746d50a6b56SStephen Hemminger 		       PG_PROC_DIR, ifname);
374739df232fSStephen Hemminger 		err = -EINVAL;
374839df232fSStephen Hemminger 		goto out2;
374939df232fSStephen Hemminger 	}
3750a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3751a553e4a6SJamal Hadi Salim 	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
3752a553e4a6SJamal Hadi Salim 	pkt_dev->ipsproto = IPPROTO_ESP;
3753a553e4a6SJamal Hadi Salim #endif
375439df232fSStephen Hemminger 
375539df232fSStephen Hemminger 	return add_dev_to_thread(t, pkt_dev);
375639df232fSStephen Hemminger out2:
375739df232fSStephen Hemminger 	dev_put(pkt_dev->odev);
375839df232fSStephen Hemminger out1:
3759a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3760a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3761a553e4a6SJamal Hadi Salim #endif
37621da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
37631da177e4SLinus Torvalds 	kfree(pkt_dev);
376439df232fSStephen Hemminger 	return err;
37651da177e4SLinus Torvalds }
37661da177e4SLinus Torvalds 
3767ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu)
37681da177e4SLinus Torvalds {
3769cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3770d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3771ee74baa7SDavid S. Miller 	struct task_struct *p;
37721da177e4SLinus Torvalds 
37733291b9dbSEric Dumazet 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
37743291b9dbSEric Dumazet 			 cpu_to_node(cpu));
37751da177e4SLinus Torvalds 	if (!t) {
3776f9467eaeSJoe Perches 		pr_err("ERROR: out of memory, can't create new thread\n");
37771da177e4SLinus Torvalds 		return -ENOMEM;
37781da177e4SLinus Torvalds 	}
37791da177e4SLinus Torvalds 
37801da177e4SLinus Torvalds 	spin_lock_init(&t->if_lock);
37811da177e4SLinus Torvalds 	t->cpu = cpu;
37821da177e4SLinus Torvalds 
3783ee74baa7SDavid S. Miller 	INIT_LIST_HEAD(&t->if_list);
3784ee74baa7SDavid S. Miller 
3785ee74baa7SDavid S. Miller 	list_add_tail(&t->th_list, &pktgen_threads);
3786d3ede327SDenis V. Lunev 	init_completion(&t->start_done);
3787ee74baa7SDavid S. Miller 
3788ee74baa7SDavid S. Miller 	p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
3789ee74baa7SDavid S. Miller 	if (IS_ERR(p)) {
3790f9467eaeSJoe Perches 		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
3791ee74baa7SDavid S. Miller 		list_del(&t->th_list);
3792ee74baa7SDavid S. Miller 		kfree(t);
3793ee74baa7SDavid S. Miller 		return PTR_ERR(p);
3794ee74baa7SDavid S. Miller 	}
3795ee74baa7SDavid S. Miller 	kthread_bind(p, cpu);
3796ee74baa7SDavid S. Miller 	t->tsk = p;
3797ee74baa7SDavid S. Miller 
37985efdccbcSDenis V. Lunev 	pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
37995efdccbcSDenis V. Lunev 			      &pktgen_thread_fops, t);
3800d50a6b56SStephen Hemminger 	if (!pe) {
3801f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3802ee74baa7SDavid S. Miller 		       PG_PROC_DIR, t->tsk->comm);
3803ee74baa7SDavid S. Miller 		kthread_stop(p);
3804ee74baa7SDavid S. Miller 		list_del(&t->th_list);
38051da177e4SLinus Torvalds 		kfree(t);
38061da177e4SLinus Torvalds 		return -EINVAL;
38071da177e4SLinus Torvalds 	}
3808d50a6b56SStephen Hemminger 
3809ee74baa7SDavid S. Miller 	wake_up_process(p);
3810d3ede327SDenis V. Lunev 	wait_for_completion(&t->start_done);
38111da177e4SLinus Torvalds 
38121da177e4SLinus Torvalds 	return 0;
38131da177e4SLinus Torvalds }
38141da177e4SLinus Torvalds 
38151da177e4SLinus Torvalds /*
38161da177e4SLinus Torvalds  * Removes a device from the thread if_list.
38171da177e4SLinus Torvalds  */
3818222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t,
3819222f1806SLuiz Capitulino 				  struct pktgen_dev *pkt_dev)
38201da177e4SLinus Torvalds {
3821c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3822c26a8016SLuiz Capitulino 	struct pktgen_dev *p;
38231da177e4SLinus Torvalds 
3824c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3825c26a8016SLuiz Capitulino 		p = list_entry(q, struct pktgen_dev, list);
3826c26a8016SLuiz Capitulino 		if (p == pkt_dev)
3827c26a8016SLuiz Capitulino 			list_del(&p->list);
38281da177e4SLinus Torvalds 	}
38291da177e4SLinus Torvalds }
38301da177e4SLinus Torvalds 
3831222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t,
3832222f1806SLuiz Capitulino 				struct pktgen_dev *pkt_dev)
38331da177e4SLinus Torvalds {
38341da177e4SLinus Torvalds 
3835f9467eaeSJoe Perches 	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
38361da177e4SLinus Torvalds 
38371da177e4SLinus Torvalds 	if (pkt_dev->running) {
3838f9467eaeSJoe Perches 		pr_warning("WARNING: trying to remove a running interface, stopping it now\n");
38391da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
38401da177e4SLinus Torvalds 	}
38411da177e4SLinus Torvalds 
38421da177e4SLinus Torvalds 	/* Dis-associate from the interface */
38431da177e4SLinus Torvalds 
38441da177e4SLinus Torvalds 	if (pkt_dev->odev) {
38451da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
38461da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
38471da177e4SLinus Torvalds 	}
38481da177e4SLinus Torvalds 
38491da177e4SLinus Torvalds 	/* And update the thread if_list */
38501da177e4SLinus Torvalds 
38511da177e4SLinus Torvalds 	_rem_dev_from_if_list(t, pkt_dev);
38521da177e4SLinus Torvalds 
385339df232fSStephen Hemminger 	if (pkt_dev->entry)
385439df232fSStephen Hemminger 		remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
38551da177e4SLinus Torvalds 
3856a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3857a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3858a553e4a6SJamal Hadi Salim #endif
38591da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
38601da177e4SLinus Torvalds 	kfree(pkt_dev);
38611da177e4SLinus Torvalds 	return 0;
38621da177e4SLinus Torvalds }
38631da177e4SLinus Torvalds 
38641da177e4SLinus Torvalds static int __init pg_init(void)
38651da177e4SLinus Torvalds {
38661da177e4SLinus Torvalds 	int cpu;
3867d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3868d50a6b56SStephen Hemminger 
3869f9467eaeSJoe Perches 	pr_info("%s", version);
38701da177e4SLinus Torvalds 
3871457c4cbcSEric W. Biederman 	pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
3872d50a6b56SStephen Hemminger 	if (!pg_proc_dir)
3873d50a6b56SStephen Hemminger 		return -ENODEV;
38741da177e4SLinus Torvalds 
387525296d59SWang Chen 	pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
3876d50a6b56SStephen Hemminger 	if (pe == NULL) {
3877f9467eaeSJoe Perches 		pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL);
3878457c4cbcSEric W. Biederman 		proc_net_remove(&init_net, PG_PROC_DIR);
38791da177e4SLinus Torvalds 		return -EINVAL;
38801da177e4SLinus Torvalds 	}
38811da177e4SLinus Torvalds 
38821da177e4SLinus Torvalds 	/* Register us to receive netdevice events */
38831da177e4SLinus Torvalds 	register_netdevice_notifier(&pktgen_notifier_block);
38841da177e4SLinus Torvalds 
3885670c02c2SJohn Hawkes 	for_each_online_cpu(cpu) {
38868024bb24SLuiz Capitulino 		int err;
38871da177e4SLinus Torvalds 
3888ee74baa7SDavid S. Miller 		err = pktgen_create_thread(cpu);
38898024bb24SLuiz Capitulino 		if (err)
3890f9467eaeSJoe Perches 			pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n",
3891f9467eaeSJoe Perches 				   cpu, err);
38921da177e4SLinus Torvalds 	}
38938024bb24SLuiz Capitulino 
38948024bb24SLuiz Capitulino 	if (list_empty(&pktgen_threads)) {
3895f9467eaeSJoe Perches 		pr_err("ERROR: Initialization failed for all threads\n");
38968024bb24SLuiz Capitulino 		unregister_netdevice_notifier(&pktgen_notifier_block);
38978024bb24SLuiz Capitulino 		remove_proc_entry(PGCTRL, pg_proc_dir);
3898457c4cbcSEric W. Biederman 		proc_net_remove(&init_net, PG_PROC_DIR);
38998024bb24SLuiz Capitulino 		return -ENODEV;
39008024bb24SLuiz Capitulino 	}
39018024bb24SLuiz Capitulino 
39021da177e4SLinus Torvalds 	return 0;
39031da177e4SLinus Torvalds }
39041da177e4SLinus Torvalds 
39051da177e4SLinus Torvalds static void __exit pg_cleanup(void)
39061da177e4SLinus Torvalds {
3907cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3908cdcdbe0bSLuiz Capitulino 	struct list_head *q, *n;
39091da177e4SLinus Torvalds 
39101da177e4SLinus Torvalds 	/* Stop all interfaces & threads */
39111da177e4SLinus Torvalds 
3912cdcdbe0bSLuiz Capitulino 	list_for_each_safe(q, n, &pktgen_threads) {
3913cdcdbe0bSLuiz Capitulino 		t = list_entry(q, struct pktgen_thread, th_list);
3914ee74baa7SDavid S. Miller 		kthread_stop(t->tsk);
3915ee74baa7SDavid S. Miller 		kfree(t);
39161da177e4SLinus Torvalds 	}
39171da177e4SLinus Torvalds 
39181da177e4SLinus Torvalds 	/* Un-register us from receiving netdevice events */
39191da177e4SLinus Torvalds 	unregister_netdevice_notifier(&pktgen_notifier_block);
39201da177e4SLinus Torvalds 
39211da177e4SLinus Torvalds 	/* Clean up proc file system */
3922d50a6b56SStephen Hemminger 	remove_proc_entry(PGCTRL, pg_proc_dir);
3923457c4cbcSEric W. Biederman 	proc_net_remove(&init_net, PG_PROC_DIR);
39241da177e4SLinus Torvalds }
39251da177e4SLinus Torvalds 
39261da177e4SLinus Torvalds module_init(pg_init);
39271da177e4SLinus Torvalds module_exit(pg_cleanup);
39281da177e4SLinus Torvalds 
3929c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
39301da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool");
39311da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3932c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION);
39331da177e4SLinus Torvalds module_param(pg_count_d, int, 0);
3934c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
39351da177e4SLinus Torvalds module_param(pg_delay_d, int, 0);
3936c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
39371da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0);
3938c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
39391da177e4SLinus Torvalds module_param(debug, int, 0);
3940c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
3941