xref: /openbmc/linux/net/core/pktgen.c (revision d618222352ac95ff9a21f1fc1018fffeb8952194)
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 {
774*d6182223SPaul Gortmaker 	int i;
7751da177e4SLinus Torvalds 	*num = 0;
7761da177e4SLinus Torvalds 
777*d6182223SPaul 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 {
792*d6182223SPaul Gortmaker 	int i;
7931da177e4SLinus Torvalds 
794*d6182223SPaul 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;
849*d6182223SPaul 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 
863*d6182223SPaul Gortmaker 	max = count;
864*d6182223SPaul 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 	}
869*d6182223SPaul 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) {
8901da177e4SLinus Torvalds 		char tb[count + 1];
8911da177e4SLinus Torvalds 		if (copy_from_user(tb, user_buffer, count))
8921da177e4SLinus Torvalds 			return -EFAULT;
8931da177e4SLinus Torvalds 		tb[count] = 0;
89425a8b254SDavid S. Miller 		printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,
895d50a6b56SStephen Hemminger 		       (unsigned long)count, tb);
8961da177e4SLinus Torvalds 	}
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	if (!strcmp(name, "min_pkt_size")) {
8991da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
90063adc6fbSStephen Hemminger 		if (len < 0)
901222f1806SLuiz Capitulino 			return len;
90263adc6fbSStephen Hemminger 
9031da177e4SLinus Torvalds 		i += len;
9041da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9051da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9061da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9071da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9081da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9091da177e4SLinus Torvalds 		}
910222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: min_pkt_size=%u",
911222f1806SLuiz Capitulino 			pkt_dev->min_pkt_size);
9121da177e4SLinus Torvalds 		return count;
9131da177e4SLinus Torvalds 	}
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	if (!strcmp(name, "max_pkt_size")) {
9161da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
91763adc6fbSStephen Hemminger 		if (len < 0)
918222f1806SLuiz Capitulino 			return len;
91963adc6fbSStephen Hemminger 
9201da177e4SLinus Torvalds 		i += len;
9211da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9221da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9231da177e4SLinus Torvalds 		if (value != pkt_dev->max_pkt_size) {
9241da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9251da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9261da177e4SLinus Torvalds 		}
927222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: max_pkt_size=%u",
928222f1806SLuiz Capitulino 			pkt_dev->max_pkt_size);
9291da177e4SLinus Torvalds 		return count;
9301da177e4SLinus Torvalds 	}
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 	/* Shortcut for min = max */
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 	if (!strcmp(name, "pkt_size")) {
9351da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
93663adc6fbSStephen Hemminger 		if (len < 0)
937222f1806SLuiz Capitulino 			return len;
93863adc6fbSStephen Hemminger 
9391da177e4SLinus Torvalds 		i += len;
9401da177e4SLinus Torvalds 		if (value < 14 + 20 + 8)
9411da177e4SLinus Torvalds 			value = 14 + 20 + 8;
9421da177e4SLinus Torvalds 		if (value != pkt_dev->min_pkt_size) {
9431da177e4SLinus Torvalds 			pkt_dev->min_pkt_size = value;
9441da177e4SLinus Torvalds 			pkt_dev->max_pkt_size = value;
9451da177e4SLinus Torvalds 			pkt_dev->cur_pkt_size = value;
9461da177e4SLinus Torvalds 		}
9471da177e4SLinus Torvalds 		sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size);
9481da177e4SLinus Torvalds 		return count;
9491da177e4SLinus Torvalds 	}
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	if (!strcmp(name, "debug")) {
9521da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
95363adc6fbSStephen Hemminger 		if (len < 0)
954222f1806SLuiz Capitulino 			return len;
95563adc6fbSStephen Hemminger 
9561da177e4SLinus Torvalds 		i += len;
9571da177e4SLinus Torvalds 		debug = value;
9581da177e4SLinus Torvalds 		sprintf(pg_result, "OK: debug=%u", debug);
9591da177e4SLinus Torvalds 		return count;
9601da177e4SLinus Torvalds 	}
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds 	if (!strcmp(name, "frags")) {
9631da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
96463adc6fbSStephen Hemminger 		if (len < 0)
965222f1806SLuiz Capitulino 			return len;
96663adc6fbSStephen Hemminger 
9671da177e4SLinus Torvalds 		i += len;
9681da177e4SLinus Torvalds 		pkt_dev->nfrags = value;
9691da177e4SLinus Torvalds 		sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags);
9701da177e4SLinus Torvalds 		return count;
9711da177e4SLinus Torvalds 	}
9721da177e4SLinus Torvalds 	if (!strcmp(name, "delay")) {
9731da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
97463adc6fbSStephen Hemminger 		if (len < 0)
975222f1806SLuiz Capitulino 			return len;
97663adc6fbSStephen Hemminger 
9771da177e4SLinus Torvalds 		i += len;
978fd29cf72SStephen Hemminger 		if (value == 0x7FFFFFFF)
979fd29cf72SStephen Hemminger 			pkt_dev->delay = ULLONG_MAX;
980fd29cf72SStephen Hemminger 		else
9819240d715SEric Dumazet 			pkt_dev->delay = (u64)value;
982fd29cf72SStephen Hemminger 
983fd29cf72SStephen Hemminger 		sprintf(pg_result, "OK: delay=%llu",
984fd29cf72SStephen Hemminger 			(unsigned long long) pkt_dev->delay);
9851da177e4SLinus Torvalds 		return count;
9861da177e4SLinus Torvalds 	}
98743d28b65SDaniel Turull 	if (!strcmp(name, "rate")) {
98843d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
98943d28b65SDaniel Turull 		if (len < 0)
99043d28b65SDaniel Turull 			return len;
99143d28b65SDaniel Turull 
99243d28b65SDaniel Turull 		i += len;
99343d28b65SDaniel Turull 		if (!value)
99443d28b65SDaniel Turull 			return len;
99543d28b65SDaniel Turull 		pkt_dev->delay = pkt_dev->min_pkt_size*8*NSEC_PER_USEC/value;
99643d28b65SDaniel Turull 		if (debug)
997f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
99843d28b65SDaniel Turull 
99943d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
100043d28b65SDaniel Turull 		return count;
100143d28b65SDaniel Turull 	}
100243d28b65SDaniel Turull 	if (!strcmp(name, "ratep")) {
100343d28b65SDaniel Turull 		len = num_arg(&user_buffer[i], 10, &value);
100443d28b65SDaniel Turull 		if (len < 0)
100543d28b65SDaniel Turull 			return len;
100643d28b65SDaniel Turull 
100743d28b65SDaniel Turull 		i += len;
100843d28b65SDaniel Turull 		if (!value)
100943d28b65SDaniel Turull 			return len;
101043d28b65SDaniel Turull 		pkt_dev->delay = NSEC_PER_SEC/value;
101143d28b65SDaniel Turull 		if (debug)
1012f9467eaeSJoe Perches 			pr_info("Delay set at: %llu ns\n", pkt_dev->delay);
101343d28b65SDaniel Turull 
101443d28b65SDaniel Turull 		sprintf(pg_result, "OK: rate=%lu", value);
101543d28b65SDaniel Turull 		return count;
101643d28b65SDaniel Turull 	}
10171da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_min")) {
10181da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
101963adc6fbSStephen Hemminger 		if (len < 0)
1020222f1806SLuiz Capitulino 			return len;
102163adc6fbSStephen Hemminger 
10221da177e4SLinus Torvalds 		i += len;
10231da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_min) {
10241da177e4SLinus Torvalds 			pkt_dev->udp_src_min = value;
10251da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10261da177e4SLinus Torvalds 		}
10271da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min);
10281da177e4SLinus Torvalds 		return count;
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_min")) {
10311da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
103263adc6fbSStephen Hemminger 		if (len < 0)
1033222f1806SLuiz Capitulino 			return len;
103463adc6fbSStephen Hemminger 
10351da177e4SLinus Torvalds 		i += len;
10361da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_min) {
10371da177e4SLinus Torvalds 			pkt_dev->udp_dst_min = value;
10381da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10391da177e4SLinus Torvalds 		}
10401da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min);
10411da177e4SLinus Torvalds 		return count;
10421da177e4SLinus Torvalds 	}
10431da177e4SLinus Torvalds 	if (!strcmp(name, "udp_src_max")) {
10441da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
104563adc6fbSStephen Hemminger 		if (len < 0)
1046222f1806SLuiz Capitulino 			return len;
104763adc6fbSStephen Hemminger 
10481da177e4SLinus Torvalds 		i += len;
10491da177e4SLinus Torvalds 		if (value != pkt_dev->udp_src_max) {
10501da177e4SLinus Torvalds 			pkt_dev->udp_src_max = value;
10511da177e4SLinus Torvalds 			pkt_dev->cur_udp_src = value;
10521da177e4SLinus Torvalds 		}
10531da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max);
10541da177e4SLinus Torvalds 		return count;
10551da177e4SLinus Torvalds 	}
10561da177e4SLinus Torvalds 	if (!strcmp(name, "udp_dst_max")) {
10571da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
105863adc6fbSStephen Hemminger 		if (len < 0)
1059222f1806SLuiz Capitulino 			return len;
106063adc6fbSStephen Hemminger 
10611da177e4SLinus Torvalds 		i += len;
10621da177e4SLinus Torvalds 		if (value != pkt_dev->udp_dst_max) {
10631da177e4SLinus Torvalds 			pkt_dev->udp_dst_max = value;
10641da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst = value;
10651da177e4SLinus Torvalds 		}
10661da177e4SLinus Torvalds 		sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max);
10671da177e4SLinus Torvalds 		return count;
10681da177e4SLinus Torvalds 	}
10691da177e4SLinus Torvalds 	if (!strcmp(name, "clone_skb")) {
10701da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
107163adc6fbSStephen Hemminger 		if (len < 0)
1072222f1806SLuiz Capitulino 			return len;
107363adc6fbSStephen Hemminger 
10741da177e4SLinus Torvalds 		i += len;
10751da177e4SLinus Torvalds 		pkt_dev->clone_skb = value;
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds 		sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb);
10781da177e4SLinus Torvalds 		return count;
10791da177e4SLinus Torvalds 	}
10801da177e4SLinus Torvalds 	if (!strcmp(name, "count")) {
10811da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
108263adc6fbSStephen Hemminger 		if (len < 0)
1083222f1806SLuiz Capitulino 			return len;
108463adc6fbSStephen Hemminger 
10851da177e4SLinus Torvalds 		i += len;
10861da177e4SLinus Torvalds 		pkt_dev->count = value;
10871da177e4SLinus Torvalds 		sprintf(pg_result, "OK: count=%llu",
10881da177e4SLinus Torvalds 			(unsigned long long)pkt_dev->count);
10891da177e4SLinus Torvalds 		return count;
10901da177e4SLinus Torvalds 	}
10911da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac_count")) {
10921da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
109363adc6fbSStephen Hemminger 		if (len < 0)
1094222f1806SLuiz Capitulino 			return len;
109563adc6fbSStephen Hemminger 
10961da177e4SLinus Torvalds 		i += len;
10971da177e4SLinus Torvalds 		if (pkt_dev->src_mac_count != value) {
10981da177e4SLinus Torvalds 			pkt_dev->src_mac_count = value;
10991da177e4SLinus Torvalds 			pkt_dev->cur_src_mac_offset = 0;
11001da177e4SLinus Torvalds 		}
1101222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: src_mac_count=%d",
1102222f1806SLuiz Capitulino 			pkt_dev->src_mac_count);
11031da177e4SLinus Torvalds 		return count;
11041da177e4SLinus Torvalds 	}
11051da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac_count")) {
11061da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
110763adc6fbSStephen Hemminger 		if (len < 0)
1108222f1806SLuiz Capitulino 			return len;
110963adc6fbSStephen Hemminger 
11101da177e4SLinus Torvalds 		i += len;
11111da177e4SLinus Torvalds 		if (pkt_dev->dst_mac_count != value) {
11121da177e4SLinus Torvalds 			pkt_dev->dst_mac_count = value;
11131da177e4SLinus Torvalds 			pkt_dev->cur_dst_mac_offset = 0;
11141da177e4SLinus Torvalds 		}
1115222f1806SLuiz Capitulino 		sprintf(pg_result, "OK: dst_mac_count=%d",
1116222f1806SLuiz Capitulino 			pkt_dev->dst_mac_count);
11171da177e4SLinus Torvalds 		return count;
11181da177e4SLinus Torvalds 	}
1119e99b99b4SRobert Olsson 	if (!strcmp(name, "node")) {
1120e99b99b4SRobert Olsson 		len = num_arg(&user_buffer[i], 10, &value);
1121e99b99b4SRobert Olsson 		if (len < 0)
1122e99b99b4SRobert Olsson 			return len;
1123e99b99b4SRobert Olsson 
1124e99b99b4SRobert Olsson 		i += len;
1125e99b99b4SRobert Olsson 
1126e99b99b4SRobert Olsson 		if (node_possible(value)) {
1127e99b99b4SRobert Olsson 			pkt_dev->node = value;
1128e99b99b4SRobert Olsson 			sprintf(pg_result, "OK: node=%d", pkt_dev->node);
1129e99b99b4SRobert Olsson 		}
1130e99b99b4SRobert Olsson 		else
1131e99b99b4SRobert Olsson 			sprintf(pg_result, "ERROR: node not possible");
1132e99b99b4SRobert Olsson 		return count;
1133e99b99b4SRobert Olsson 	}
11341da177e4SLinus Torvalds 	if (!strcmp(name, "flag")) {
11351da177e4SLinus Torvalds 		char f[32];
11361da177e4SLinus Torvalds 		memset(f, 0, 32);
11371da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
113863adc6fbSStephen Hemminger 		if (len < 0)
1139222f1806SLuiz Capitulino 			return len;
114063adc6fbSStephen Hemminger 
11411da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
11421da177e4SLinus Torvalds 			return -EFAULT;
11431da177e4SLinus Torvalds 		i += len;
11441da177e4SLinus Torvalds 		if (strcmp(f, "IPSRC_RND") == 0)
11451da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPSRC_RND;
11461da177e4SLinus Torvalds 
11471da177e4SLinus Torvalds 		else if (strcmp(f, "!IPSRC_RND") == 0)
11481da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPSRC_RND;
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 		else if (strcmp(f, "TXSIZE_RND") == 0)
11511da177e4SLinus Torvalds 			pkt_dev->flags |= F_TXSIZE_RND;
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 		else if (strcmp(f, "!TXSIZE_RND") == 0)
11541da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_TXSIZE_RND;
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 		else if (strcmp(f, "IPDST_RND") == 0)
11571da177e4SLinus Torvalds 			pkt_dev->flags |= F_IPDST_RND;
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 		else if (strcmp(f, "!IPDST_RND") == 0)
11601da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_IPDST_RND;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 		else if (strcmp(f, "UDPSRC_RND") == 0)
11631da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPSRC_RND;
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPSRC_RND") == 0)
11661da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPSRC_RND;
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 		else if (strcmp(f, "UDPDST_RND") == 0)
11691da177e4SLinus Torvalds 			pkt_dev->flags |= F_UDPDST_RND;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 		else if (strcmp(f, "!UDPDST_RND") == 0)
11721da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_UDPDST_RND;
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 		else if (strcmp(f, "MACSRC_RND") == 0)
11751da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACSRC_RND;
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds 		else if (strcmp(f, "!MACSRC_RND") == 0)
11781da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACSRC_RND;
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 		else if (strcmp(f, "MACDST_RND") == 0)
11811da177e4SLinus Torvalds 			pkt_dev->flags |= F_MACDST_RND;
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 		else if (strcmp(f, "!MACDST_RND") == 0)
11841da177e4SLinus Torvalds 			pkt_dev->flags &= ~F_MACDST_RND;
11851da177e4SLinus Torvalds 
1186ca6549afSSteven Whitehouse 		else if (strcmp(f, "MPLS_RND") == 0)
1187ca6549afSSteven Whitehouse 			pkt_dev->flags |= F_MPLS_RND;
1188ca6549afSSteven Whitehouse 
1189ca6549afSSteven Whitehouse 		else if (strcmp(f, "!MPLS_RND") == 0)
1190ca6549afSSteven Whitehouse 			pkt_dev->flags &= ~F_MPLS_RND;
1191ca6549afSSteven Whitehouse 
119234954ddcSFrancesco Fondelli 		else if (strcmp(f, "VID_RND") == 0)
119334954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_VID_RND;
119434954ddcSFrancesco Fondelli 
119534954ddcSFrancesco Fondelli 		else if (strcmp(f, "!VID_RND") == 0)
119634954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_VID_RND;
119734954ddcSFrancesco Fondelli 
119834954ddcSFrancesco Fondelli 		else if (strcmp(f, "SVID_RND") == 0)
119934954ddcSFrancesco Fondelli 			pkt_dev->flags |= F_SVID_RND;
120034954ddcSFrancesco Fondelli 
120134954ddcSFrancesco Fondelli 		else if (strcmp(f, "!SVID_RND") == 0)
120234954ddcSFrancesco Fondelli 			pkt_dev->flags &= ~F_SVID_RND;
120334954ddcSFrancesco Fondelli 
1204007a531bSJamal Hadi Salim 		else if (strcmp(f, "FLOW_SEQ") == 0)
1205007a531bSJamal Hadi Salim 			pkt_dev->flags |= F_FLOW_SEQ;
1206007a531bSJamal Hadi Salim 
120745b270f8SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_RND") == 0)
120845b270f8SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_RND;
120945b270f8SRobert Olsson 
121045b270f8SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
121145b270f8SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_RND;
1212e6fce5b9SRobert Olsson 
1213e6fce5b9SRobert Olsson 		else if (strcmp(f, "QUEUE_MAP_CPU") == 0)
1214e6fce5b9SRobert Olsson 			pkt_dev->flags |= F_QUEUE_MAP_CPU;
1215e6fce5b9SRobert Olsson 
1216e6fce5b9SRobert Olsson 		else if (strcmp(f, "!QUEUE_MAP_CPU") == 0)
1217e6fce5b9SRobert Olsson 			pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
1218a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
1219a553e4a6SJamal Hadi Salim 		else if (strcmp(f, "IPSEC") == 0)
1220a553e4a6SJamal Hadi Salim 			pkt_dev->flags |= F_IPSEC_ON;
1221a553e4a6SJamal Hadi Salim #endif
1222a553e4a6SJamal Hadi Salim 
12231ca7768cSFrancesco Fondelli 		else if (strcmp(f, "!IPV6") == 0)
12241ca7768cSFrancesco Fondelli 			pkt_dev->flags &= ~F_IPV6;
12251ca7768cSFrancesco Fondelli 
1226e99b99b4SRobert Olsson 		else if (strcmp(f, "NODE_ALLOC") == 0)
1227e99b99b4SRobert Olsson 			pkt_dev->flags |= F_NODE;
1228e99b99b4SRobert Olsson 
1229e99b99b4SRobert Olsson 		else if (strcmp(f, "!NODE_ALLOC") == 0)
1230e99b99b4SRobert Olsson 			pkt_dev->flags &= ~F_NODE;
1231e99b99b4SRobert Olsson 
12321da177e4SLinus Torvalds 		else {
1233222f1806SLuiz Capitulino 			sprintf(pg_result,
1234222f1806SLuiz Capitulino 				"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
12351da177e4SLinus Torvalds 				f,
12361ca7768cSFrancesco Fondelli 				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
1237e99b99b4SRobert Olsson 				"MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n");
12381da177e4SLinus Torvalds 			return count;
12391da177e4SLinus Torvalds 		}
12401da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
12411da177e4SLinus Torvalds 		return count;
12421da177e4SLinus Torvalds 	}
12431da177e4SLinus Torvalds 	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
12441da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
124563adc6fbSStephen Hemminger 		if (len < 0)
1246222f1806SLuiz Capitulino 			return len;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12491da177e4SLinus Torvalds 			return -EFAULT;
12501da177e4SLinus Torvalds 		buf[len] = 0;
12511da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_min) != 0) {
12521da177e4SLinus Torvalds 			memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min));
12531da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_min, buf, len);
12541da177e4SLinus Torvalds 			pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
12551da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_min;
12561da177e4SLinus Torvalds 		}
12571da177e4SLinus Torvalds 		if (debug)
125825a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
1259222f1806SLuiz Capitulino 			       pkt_dev->dst_min);
12601da177e4SLinus Torvalds 		i += len;
12611da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
12621da177e4SLinus Torvalds 		return count;
12631da177e4SLinus Torvalds 	}
12641da177e4SLinus Torvalds 	if (!strcmp(name, "dst_max")) {
12651da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
126663adc6fbSStephen Hemminger 		if (len < 0)
1267222f1806SLuiz Capitulino 			return len;
126863adc6fbSStephen Hemminger 
12691da177e4SLinus Torvalds 
12701da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12711da177e4SLinus Torvalds 			return -EFAULT;
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds 		buf[len] = 0;
12741da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->dst_max) != 0) {
12751da177e4SLinus Torvalds 			memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max));
12761da177e4SLinus Torvalds 			strncpy(pkt_dev->dst_max, buf, len);
12771da177e4SLinus Torvalds 			pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
12781da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->daddr_max;
12791da177e4SLinus Torvalds 		}
12801da177e4SLinus Torvalds 		if (debug)
128125a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
1282222f1806SLuiz Capitulino 			       pkt_dev->dst_max);
12831da177e4SLinus Torvalds 		i += len;
12841da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
12851da177e4SLinus Torvalds 		return count;
12861da177e4SLinus Torvalds 	}
12871da177e4SLinus Torvalds 	if (!strcmp(name, "dst6")) {
12881da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1289222f1806SLuiz Capitulino 		if (len < 0)
1290222f1806SLuiz Capitulino 			return len;
12911da177e4SLinus Torvalds 
12921da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
12951da177e4SLinus Torvalds 			return -EFAULT;
12961da177e4SLinus Torvalds 		buf[len] = 0;
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->in6_daddr.s6_addr);
12991da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr);
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 		ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds 		if (debug)
130425a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds 		i += len;
13071da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6=%s", buf);
13081da177e4SLinus Torvalds 		return count;
13091da177e4SLinus Torvalds 	}
13101da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_min")) {
13111da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1312222f1806SLuiz Capitulino 		if (len < 0)
1313222f1806SLuiz Capitulino 			return len;
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13181da177e4SLinus Torvalds 			return -EFAULT;
13191da177e4SLinus Torvalds 		buf[len] = 0;
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
13221da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr);
13231da177e4SLinus Torvalds 
1324222f1806SLuiz Capitulino 		ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
1325222f1806SLuiz Capitulino 			       &pkt_dev->min_in6_daddr);
13261da177e4SLinus Torvalds 		if (debug)
132725a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 		i += len;
13301da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_min=%s", buf);
13311da177e4SLinus Torvalds 		return count;
13321da177e4SLinus Torvalds 	}
13331da177e4SLinus Torvalds 	if (!strcmp(name, "dst6_max")) {
13341da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1335222f1806SLuiz Capitulino 		if (len < 0)
1336222f1806SLuiz Capitulino 			return len;
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13411da177e4SLinus Torvalds 			return -EFAULT;
13421da177e4SLinus Torvalds 		buf[len] = 0;
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
13451da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 		if (debug)
134825a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds 		i += len;
13511da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dst6_max=%s", buf);
13521da177e4SLinus Torvalds 		return count;
13531da177e4SLinus Torvalds 	}
13541da177e4SLinus Torvalds 	if (!strcmp(name, "src6")) {
13551da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(buf) - 1);
1356222f1806SLuiz Capitulino 		if (len < 0)
1357222f1806SLuiz Capitulino 			return len;
13581da177e4SLinus Torvalds 
13591da177e4SLinus Torvalds 		pkt_dev->flags |= F_IPV6;
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13621da177e4SLinus Torvalds 			return -EFAULT;
13631da177e4SLinus Torvalds 		buf[len] = 0;
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 		scan_ip6(buf, pkt_dev->in6_saddr.s6_addr);
13661da177e4SLinus Torvalds 		fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr);
13671da177e4SLinus Torvalds 
13681da177e4SLinus Torvalds 		ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 		if (debug)
137125a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds 		i += len;
13741da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src6=%s", buf);
13751da177e4SLinus Torvalds 		return count;
13761da177e4SLinus Torvalds 	}
13771da177e4SLinus Torvalds 	if (!strcmp(name, "src_min")) {
13781da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
137963adc6fbSStephen Hemminger 		if (len < 0)
1380222f1806SLuiz Capitulino 			return len;
138163adc6fbSStephen Hemminger 
13821da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
13831da177e4SLinus Torvalds 			return -EFAULT;
13841da177e4SLinus Torvalds 		buf[len] = 0;
13851da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_min) != 0) {
13861da177e4SLinus Torvalds 			memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min));
13871da177e4SLinus Torvalds 			strncpy(pkt_dev->src_min, buf, len);
13881da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
13891da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_min;
13901da177e4SLinus Torvalds 		}
13911da177e4SLinus Torvalds 		if (debug)
139225a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
1393222f1806SLuiz Capitulino 			       pkt_dev->src_min);
13941da177e4SLinus Torvalds 		i += len;
13951da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
13961da177e4SLinus Torvalds 		return count;
13971da177e4SLinus Torvalds 	}
13981da177e4SLinus Torvalds 	if (!strcmp(name, "src_max")) {
13991da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
140063adc6fbSStephen Hemminger 		if (len < 0)
1401222f1806SLuiz Capitulino 			return len;
140263adc6fbSStephen Hemminger 
14031da177e4SLinus Torvalds 		if (copy_from_user(buf, &user_buffer[i], len))
14041da177e4SLinus Torvalds 			return -EFAULT;
14051da177e4SLinus Torvalds 		buf[len] = 0;
14061da177e4SLinus Torvalds 		if (strcmp(buf, pkt_dev->src_max) != 0) {
14071da177e4SLinus Torvalds 			memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max));
14081da177e4SLinus Torvalds 			strncpy(pkt_dev->src_max, buf, len);
14091da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
14101da177e4SLinus Torvalds 			pkt_dev->cur_saddr = pkt_dev->saddr_max;
14111da177e4SLinus Torvalds 		}
14121da177e4SLinus Torvalds 		if (debug)
141325a8b254SDavid S. Miller 			printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
1414222f1806SLuiz Capitulino 			       pkt_dev->src_max);
14151da177e4SLinus Torvalds 		i += len;
14161da177e4SLinus Torvalds 		sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
14171da177e4SLinus Torvalds 		return count;
14181da177e4SLinus Torvalds 	}
14191da177e4SLinus Torvalds 	if (!strcmp(name, "dst_mac")) {
14201da177e4SLinus Torvalds 		char *v = valstr;
1421f404e9a6SKris Katterjohn 		unsigned char old_dmac[ETH_ALEN];
14221da177e4SLinus Torvalds 		unsigned char *m = pkt_dev->dst_mac;
1423f404e9a6SKris Katterjohn 		memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN);
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
142663adc6fbSStephen Hemminger 		if (len < 0)
1427222f1806SLuiz Capitulino 			return len;
142863adc6fbSStephen Hemminger 
14291da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14301da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14311da177e4SLinus Torvalds 			return -EFAULT;
14321da177e4SLinus Torvalds 		i += len;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 		for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) {
1435451e07a2SAndy Shevchenko 			int value;
1436451e07a2SAndy Shevchenko 
1437451e07a2SAndy Shevchenko 			value = hex_to_bin(*v);
1438451e07a2SAndy Shevchenko 			if (value >= 0)
1439451e07a2SAndy Shevchenko 				*m = *m * 16 + value;
1440451e07a2SAndy Shevchenko 
14411da177e4SLinus Torvalds 			if (*v == ':') {
14421da177e4SLinus Torvalds 				m++;
14431da177e4SLinus Torvalds 				*m = 0;
14441da177e4SLinus Torvalds 			}
14451da177e4SLinus Torvalds 		}
14461da177e4SLinus Torvalds 
14471da177e4SLinus Torvalds 		/* Set up Dest MAC */
1448f404e9a6SKris Katterjohn 		if (compare_ether_addr(old_dmac, pkt_dev->dst_mac))
1449f404e9a6SKris Katterjohn 			memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 		sprintf(pg_result, "OK: dstmac");
14521da177e4SLinus Torvalds 		return count;
14531da177e4SLinus Torvalds 	}
14541da177e4SLinus Torvalds 	if (!strcmp(name, "src_mac")) {
14551da177e4SLinus Torvalds 		char *v = valstr;
1456ce5d0b47SAdit Ranadive 		unsigned char old_smac[ETH_ALEN];
14571da177e4SLinus Torvalds 		unsigned char *m = pkt_dev->src_mac;
14581da177e4SLinus Torvalds 
1459ce5d0b47SAdit Ranadive 		memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
1460ce5d0b47SAdit Ranadive 
14611da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
146263adc6fbSStephen Hemminger 		if (len < 0)
1463222f1806SLuiz Capitulino 			return len;
146463adc6fbSStephen Hemminger 
14651da177e4SLinus Torvalds 		memset(valstr, 0, sizeof(valstr));
14661da177e4SLinus Torvalds 		if (copy_from_user(valstr, &user_buffer[i], len))
14671da177e4SLinus Torvalds 			return -EFAULT;
14681da177e4SLinus Torvalds 		i += len;
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds 		for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) {
1471451e07a2SAndy Shevchenko 			int value;
1472451e07a2SAndy Shevchenko 
1473451e07a2SAndy Shevchenko 			value = hex_to_bin(*v);
1474451e07a2SAndy Shevchenko 			if (value >= 0)
1475451e07a2SAndy Shevchenko 				*m = *m * 16 + value;
1476451e07a2SAndy Shevchenko 
14771da177e4SLinus Torvalds 			if (*v == ':') {
14781da177e4SLinus Torvalds 				m++;
14791da177e4SLinus Torvalds 				*m = 0;
14801da177e4SLinus Torvalds 			}
14811da177e4SLinus Torvalds 		}
14821da177e4SLinus Torvalds 
1483ce5d0b47SAdit Ranadive 		/* Set up Src MAC */
1484ce5d0b47SAdit Ranadive 		if (compare_ether_addr(old_smac, pkt_dev->src_mac))
1485ce5d0b47SAdit Ranadive 			memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
1486ce5d0b47SAdit Ranadive 
14871da177e4SLinus Torvalds 		sprintf(pg_result, "OK: srcmac");
14881da177e4SLinus Torvalds 		return count;
14891da177e4SLinus Torvalds 	}
14901da177e4SLinus Torvalds 
14911da177e4SLinus Torvalds 	if (!strcmp(name, "clear_counters")) {
14921da177e4SLinus Torvalds 		pktgen_clear_counters(pkt_dev);
14931da177e4SLinus Torvalds 		sprintf(pg_result, "OK: Clearing counters.\n");
14941da177e4SLinus Torvalds 		return count;
14951da177e4SLinus Torvalds 	}
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	if (!strcmp(name, "flows")) {
14981da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
149963adc6fbSStephen Hemminger 		if (len < 0)
1500222f1806SLuiz Capitulino 			return len;
150163adc6fbSStephen Hemminger 
15021da177e4SLinus Torvalds 		i += len;
15031da177e4SLinus Torvalds 		if (value > MAX_CFLOWS)
15041da177e4SLinus Torvalds 			value = MAX_CFLOWS;
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds 		pkt_dev->cflows = value;
15071da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
15081da177e4SLinus Torvalds 		return count;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 	if (!strcmp(name, "flowlen")) {
15121da177e4SLinus Torvalds 		len = num_arg(&user_buffer[i], 10, &value);
151363adc6fbSStephen Hemminger 		if (len < 0)
1514222f1806SLuiz Capitulino 			return len;
151563adc6fbSStephen Hemminger 
15161da177e4SLinus Torvalds 		i += len;
15171da177e4SLinus Torvalds 		pkt_dev->lflow = value;
15181da177e4SLinus Torvalds 		sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow);
15191da177e4SLinus Torvalds 		return count;
15201da177e4SLinus Torvalds 	}
15211da177e4SLinus Torvalds 
152245b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_min")) {
152345b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
152463adc6fbSStephen Hemminger 		if (len < 0)
152545b270f8SRobert Olsson 			return len;
152663adc6fbSStephen Hemminger 
152745b270f8SRobert Olsson 		i += len;
152845b270f8SRobert Olsson 		pkt_dev->queue_map_min = value;
152945b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
153045b270f8SRobert Olsson 		return count;
153145b270f8SRobert Olsson 	}
153245b270f8SRobert Olsson 
153345b270f8SRobert Olsson 	if (!strcmp(name, "queue_map_max")) {
153445b270f8SRobert Olsson 		len = num_arg(&user_buffer[i], 5, &value);
153563adc6fbSStephen Hemminger 		if (len < 0)
153645b270f8SRobert Olsson 			return len;
153763adc6fbSStephen Hemminger 
153845b270f8SRobert Olsson 		i += len;
153945b270f8SRobert Olsson 		pkt_dev->queue_map_max = value;
154045b270f8SRobert Olsson 		sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
154145b270f8SRobert Olsson 		return count;
154245b270f8SRobert Olsson 	}
154345b270f8SRobert Olsson 
1544ca6549afSSteven Whitehouse 	if (!strcmp(name, "mpls")) {
1545cfcabdccSStephen Hemminger 		unsigned n, cnt;
1546cfcabdccSStephen Hemminger 
1547ca6549afSSteven Whitehouse 		len = get_labels(&user_buffer[i], pkt_dev);
1548cfcabdccSStephen Hemminger 		if (len < 0)
1549cfcabdccSStephen Hemminger 			return len;
1550ca6549afSSteven Whitehouse 		i += len;
1551cfcabdccSStephen Hemminger 		cnt = sprintf(pg_result, "OK: mpls=");
1552ca6549afSSteven Whitehouse 		for (n = 0; n < pkt_dev->nr_labels; n++)
1553cfcabdccSStephen Hemminger 			cnt += sprintf(pg_result + cnt,
1554ca6549afSSteven Whitehouse 				       "%08x%s", ntohl(pkt_dev->labels[n]),
1555ca6549afSSteven Whitehouse 				       n == pkt_dev->nr_labels-1 ? "" : ",");
155634954ddcSFrancesco Fondelli 
155734954ddcSFrancesco Fondelli 		if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
155834954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
155934954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
156034954ddcSFrancesco Fondelli 
156134954ddcSFrancesco Fondelli 			if (debug)
156225a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
156334954ddcSFrancesco Fondelli 		}
156434954ddcSFrancesco Fondelli 		return count;
156534954ddcSFrancesco Fondelli 	}
156634954ddcSFrancesco Fondelli 
156734954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_id")) {
156834954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
156963adc6fbSStephen Hemminger 		if (len < 0)
157034954ddcSFrancesco Fondelli 			return len;
157163adc6fbSStephen Hemminger 
157234954ddcSFrancesco Fondelli 		i += len;
157334954ddcSFrancesco Fondelli 		if (value <= 4095) {
157434954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = value;  /* turn on VLAN */
157534954ddcSFrancesco Fondelli 
157634954ddcSFrancesco Fondelli 			if (debug)
157725a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN turned on\n");
157834954ddcSFrancesco Fondelli 
157934954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
158025a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
158134954ddcSFrancesco Fondelli 
158234954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
158334954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
158434954ddcSFrancesco Fondelli 		} else {
158534954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
158634954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
158734954ddcSFrancesco Fondelli 
158834954ddcSFrancesco Fondelli 			if (debug)
158925a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
159034954ddcSFrancesco Fondelli 		}
159134954ddcSFrancesco Fondelli 		return count;
159234954ddcSFrancesco Fondelli 	}
159334954ddcSFrancesco Fondelli 
159434954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_p")) {
159534954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
159663adc6fbSStephen Hemminger 		if (len < 0)
159734954ddcSFrancesco Fondelli 			return len;
159863adc6fbSStephen Hemminger 
159934954ddcSFrancesco Fondelli 		i += len;
160034954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
160134954ddcSFrancesco Fondelli 			pkt_dev->vlan_p = value;
160234954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
160334954ddcSFrancesco Fondelli 		} else {
160434954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_p must be 0-7");
160534954ddcSFrancesco Fondelli 		}
160634954ddcSFrancesco Fondelli 		return count;
160734954ddcSFrancesco Fondelli 	}
160834954ddcSFrancesco Fondelli 
160934954ddcSFrancesco Fondelli 	if (!strcmp(name, "vlan_cfi")) {
161034954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
161163adc6fbSStephen Hemminger 		if (len < 0)
161234954ddcSFrancesco Fondelli 			return len;
161363adc6fbSStephen Hemminger 
161434954ddcSFrancesco Fondelli 		i += len;
161534954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
161634954ddcSFrancesco Fondelli 			pkt_dev->vlan_cfi = value;
161734954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
161834954ddcSFrancesco Fondelli 		} else {
161934954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
162034954ddcSFrancesco Fondelli 		}
162134954ddcSFrancesco Fondelli 		return count;
162234954ddcSFrancesco Fondelli 	}
162334954ddcSFrancesco Fondelli 
162434954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_id")) {
162534954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 4, &value);
162663adc6fbSStephen Hemminger 		if (len < 0)
162734954ddcSFrancesco Fondelli 			return len;
162863adc6fbSStephen Hemminger 
162934954ddcSFrancesco Fondelli 		i += len;
163034954ddcSFrancesco Fondelli 		if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
163134954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = value;  /* turn on SVLAN */
163234954ddcSFrancesco Fondelli 
163334954ddcSFrancesco Fondelli 			if (debug)
163425a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
163534954ddcSFrancesco Fondelli 
163634954ddcSFrancesco Fondelli 			if (debug && pkt_dev->nr_labels)
163725a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
163834954ddcSFrancesco Fondelli 
163934954ddcSFrancesco Fondelli 			pkt_dev->nr_labels = 0;    /* turn off MPLS */
164034954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
164134954ddcSFrancesco Fondelli 		} else {
164234954ddcSFrancesco Fondelli 			pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
164334954ddcSFrancesco Fondelli 			pkt_dev->svlan_id = 0xffff;
164434954ddcSFrancesco Fondelli 
164534954ddcSFrancesco Fondelli 			if (debug)
164625a8b254SDavid S. Miller 				printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
164734954ddcSFrancesco Fondelli 		}
164834954ddcSFrancesco Fondelli 		return count;
164934954ddcSFrancesco Fondelli 	}
165034954ddcSFrancesco Fondelli 
165134954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_p")) {
165234954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
165363adc6fbSStephen Hemminger 		if (len < 0)
165434954ddcSFrancesco Fondelli 			return len;
165563adc6fbSStephen Hemminger 
165634954ddcSFrancesco Fondelli 		i += len;
165734954ddcSFrancesco Fondelli 		if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
165834954ddcSFrancesco Fondelli 			pkt_dev->svlan_p = value;
165934954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
166034954ddcSFrancesco Fondelli 		} else {
166134954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_p must be 0-7");
166234954ddcSFrancesco Fondelli 		}
166334954ddcSFrancesco Fondelli 		return count;
166434954ddcSFrancesco Fondelli 	}
166534954ddcSFrancesco Fondelli 
166634954ddcSFrancesco Fondelli 	if (!strcmp(name, "svlan_cfi")) {
166734954ddcSFrancesco Fondelli 		len = num_arg(&user_buffer[i], 1, &value);
166863adc6fbSStephen Hemminger 		if (len < 0)
166934954ddcSFrancesco Fondelli 			return len;
167063adc6fbSStephen Hemminger 
167134954ddcSFrancesco Fondelli 		i += len;
167234954ddcSFrancesco Fondelli 		if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
167334954ddcSFrancesco Fondelli 			pkt_dev->svlan_cfi = value;
167434954ddcSFrancesco Fondelli 			sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
167534954ddcSFrancesco Fondelli 		} else {
167634954ddcSFrancesco Fondelli 			sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
167734954ddcSFrancesco Fondelli 		}
1678ca6549afSSteven Whitehouse 		return count;
1679ca6549afSSteven Whitehouse 	}
1680ca6549afSSteven Whitehouse 
16811ca7768cSFrancesco Fondelli 	if (!strcmp(name, "tos")) {
16821ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
16831ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
168463adc6fbSStephen Hemminger 		if (len < 0)
16851ca7768cSFrancesco Fondelli 			return len;
168663adc6fbSStephen Hemminger 
16871ca7768cSFrancesco Fondelli 		i += len;
16881ca7768cSFrancesco Fondelli 		if (len == 2) {
16891ca7768cSFrancesco Fondelli 			pkt_dev->tos = tmp_value;
16901ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
16911ca7768cSFrancesco Fondelli 		} else {
16921ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: tos must be 00-ff");
16931ca7768cSFrancesco Fondelli 		}
16941ca7768cSFrancesco Fondelli 		return count;
16951ca7768cSFrancesco Fondelli 	}
16961ca7768cSFrancesco Fondelli 
16971ca7768cSFrancesco Fondelli 	if (!strcmp(name, "traffic_class")) {
16981ca7768cSFrancesco Fondelli 		__u32 tmp_value = 0;
16991ca7768cSFrancesco Fondelli 		len = hex32_arg(&user_buffer[i], 2, &tmp_value);
170063adc6fbSStephen Hemminger 		if (len < 0)
17011ca7768cSFrancesco Fondelli 			return len;
170263adc6fbSStephen Hemminger 
17031ca7768cSFrancesco Fondelli 		i += len;
17041ca7768cSFrancesco Fondelli 		if (len == 2) {
17051ca7768cSFrancesco Fondelli 			pkt_dev->traffic_class = tmp_value;
17061ca7768cSFrancesco Fondelli 			sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
17071ca7768cSFrancesco Fondelli 		} else {
17081ca7768cSFrancesco Fondelli 			sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
17091ca7768cSFrancesco Fondelli 		}
17101ca7768cSFrancesco Fondelli 		return count;
17111ca7768cSFrancesco Fondelli 	}
17121ca7768cSFrancesco Fondelli 
17131da177e4SLinus Torvalds 	sprintf(pkt_dev->result, "No such parameter \"%s\"", name);
17141da177e4SLinus Torvalds 	return -EINVAL;
17151da177e4SLinus Torvalds }
17161da177e4SLinus Torvalds 
1717d50a6b56SStephen Hemminger static int pktgen_if_open(struct inode *inode, struct file *file)
17181da177e4SLinus Torvalds {
1719d50a6b56SStephen Hemminger 	return single_open(file, pktgen_if_show, PDE(inode)->data);
17201da177e4SLinus Torvalds }
17211da177e4SLinus Torvalds 
17229a32144eSArjan van de Ven static const struct file_operations pktgen_if_fops = {
1723d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1724d50a6b56SStephen Hemminger 	.open    = pktgen_if_open,
1725d50a6b56SStephen Hemminger 	.read    = seq_read,
1726d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1727d50a6b56SStephen Hemminger 	.write   = pktgen_if_write,
1728d50a6b56SStephen Hemminger 	.release = single_release,
1729d50a6b56SStephen Hemminger };
1730d50a6b56SStephen Hemminger 
1731d50a6b56SStephen Hemminger static int pktgen_thread_show(struct seq_file *seq, void *v)
1732d50a6b56SStephen Hemminger {
1733d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1734648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
1735d50a6b56SStephen Hemminger 
1736d50a6b56SStephen Hemminger 	BUG_ON(!t);
1737d50a6b56SStephen Hemminger 
1738d50a6b56SStephen Hemminger 	seq_printf(seq, "Running: ");
17391da177e4SLinus Torvalds 
17401da177e4SLinus Torvalds 	if_lock(t);
1741c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
17421da177e4SLinus Torvalds 		if (pkt_dev->running)
1743593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17441da177e4SLinus Torvalds 
1745d50a6b56SStephen Hemminger 	seq_printf(seq, "\nStopped: ");
17461da177e4SLinus Torvalds 
1747c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
17481da177e4SLinus Torvalds 		if (!pkt_dev->running)
1749593f63b0SEric Dumazet 			seq_printf(seq, "%s ", pkt_dev->odevname);
17501da177e4SLinus Torvalds 
17511da177e4SLinus Torvalds 	if (t->result[0])
1752d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: %s\n", t->result);
17531da177e4SLinus Torvalds 	else
1754d50a6b56SStephen Hemminger 		seq_printf(seq, "\nResult: NA\n");
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds 	if_unlock(t);
17571da177e4SLinus Torvalds 
1758d50a6b56SStephen Hemminger 	return 0;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds 
1761d50a6b56SStephen Hemminger static ssize_t pktgen_thread_write(struct file *file,
1762d50a6b56SStephen Hemminger 				   const char __user * user_buffer,
1763d50a6b56SStephen Hemminger 				   size_t count, loff_t * offset)
17641da177e4SLinus Torvalds {
17658a994a71SJoe Perches 	struct seq_file *seq = file->private_data;
1766d50a6b56SStephen Hemminger 	struct pktgen_thread *t = seq->private;
1767*d6182223SPaul Gortmaker 	int i, max, len, ret;
17681da177e4SLinus Torvalds 	char name[40];
17691da177e4SLinus Torvalds 	char *pg_result;
17701da177e4SLinus Torvalds 
17711da177e4SLinus Torvalds 	if (count < 1) {
17721da177e4SLinus Torvalds 		//      sprintf(pg_result, "Wrong command format");
17731da177e4SLinus Torvalds 		return -EINVAL;
17741da177e4SLinus Torvalds 	}
17751da177e4SLinus Torvalds 
1776*d6182223SPaul Gortmaker 	max = count;
1777*d6182223SPaul Gortmaker 	len = count_trail_chars(user_buffer, max);
17781da177e4SLinus Torvalds 	if (len < 0)
17791da177e4SLinus Torvalds 		return len;
17801da177e4SLinus Torvalds 
1781*d6182223SPaul Gortmaker 	i = len;
17821da177e4SLinus Torvalds 
17831da177e4SLinus Torvalds 	/* Read variable name */
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 	len = strn_len(&user_buffer[i], sizeof(name) - 1);
17861da177e4SLinus Torvalds 	if (len < 0)
17871da177e4SLinus Torvalds 		return len;
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds 	memset(name, 0, sizeof(name));
17901da177e4SLinus Torvalds 	if (copy_from_user(name, &user_buffer[i], len))
17911da177e4SLinus Torvalds 		return -EFAULT;
17921da177e4SLinus Torvalds 	i += len;
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 	max = count - i;
17951da177e4SLinus Torvalds 	len = count_trail_chars(&user_buffer[i], max);
17961da177e4SLinus Torvalds 	if (len < 0)
17971da177e4SLinus Torvalds 		return len;
17981da177e4SLinus Torvalds 
17991da177e4SLinus Torvalds 	i += len;
18001da177e4SLinus Torvalds 
18011da177e4SLinus Torvalds 	if (debug)
180225a8b254SDavid S. Miller 		printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
180325a8b254SDavid S. Miller 		       name, (unsigned long)count);
18041da177e4SLinus Torvalds 
18051da177e4SLinus Torvalds 	if (!t) {
1806f9467eaeSJoe Perches 		pr_err("ERROR: No thread\n");
18071da177e4SLinus Torvalds 		ret = -EINVAL;
18081da177e4SLinus Torvalds 		goto out;
18091da177e4SLinus Torvalds 	}
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds 	pg_result = &(t->result[0]);
18121da177e4SLinus Torvalds 
18131da177e4SLinus Torvalds 	if (!strcmp(name, "add_device")) {
18141da177e4SLinus Torvalds 		char f[32];
18151da177e4SLinus Torvalds 		memset(f, 0, 32);
18161da177e4SLinus Torvalds 		len = strn_len(&user_buffer[i], sizeof(f) - 1);
18171da177e4SLinus Torvalds 		if (len < 0) {
18181da177e4SLinus Torvalds 			ret = len;
18191da177e4SLinus Torvalds 			goto out;
18201da177e4SLinus Torvalds 		}
18211da177e4SLinus Torvalds 		if (copy_from_user(f, &user_buffer[i], len))
18221da177e4SLinus Torvalds 			return -EFAULT;
18231da177e4SLinus Torvalds 		i += len;
18246146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
18251da177e4SLinus Torvalds 		pktgen_add_device(t, f);
18266146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
18271da177e4SLinus Torvalds 		ret = count;
18281da177e4SLinus Torvalds 		sprintf(pg_result, "OK: add_device=%s", f);
18291da177e4SLinus Torvalds 		goto out;
18301da177e4SLinus Torvalds 	}
18311da177e4SLinus Torvalds 
18321da177e4SLinus Torvalds 	if (!strcmp(name, "rem_device_all")) {
18336146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
183495ed63f7SArthur Kepner 		t->control |= T_REMDEVALL;
18356146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1836121caf57SNishanth Aravamudan 		schedule_timeout_interruptible(msecs_to_jiffies(125));	/* Propagate thread->control  */
18371da177e4SLinus Torvalds 		ret = count;
18381da177e4SLinus Torvalds 		sprintf(pg_result, "OK: rem_device_all");
18391da177e4SLinus Torvalds 		goto out;
18401da177e4SLinus Torvalds 	}
18411da177e4SLinus Torvalds 
18421da177e4SLinus Torvalds 	if (!strcmp(name, "max_before_softirq")) {
1843b163911fSRobert Olsson 		sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
18441da177e4SLinus Torvalds 		ret = count;
18451da177e4SLinus Torvalds 		goto out;
18461da177e4SLinus Torvalds 	}
18471da177e4SLinus Torvalds 
18481da177e4SLinus Torvalds 	ret = -EINVAL;
18491da177e4SLinus Torvalds out:
18501da177e4SLinus Torvalds 	return ret;
18511da177e4SLinus Torvalds }
18521da177e4SLinus Torvalds 
1853d50a6b56SStephen Hemminger static int pktgen_thread_open(struct inode *inode, struct file *file)
18541da177e4SLinus Torvalds {
1855d50a6b56SStephen Hemminger 	return single_open(file, pktgen_thread_show, PDE(inode)->data);
18561da177e4SLinus Torvalds }
18571da177e4SLinus Torvalds 
18589a32144eSArjan van de Ven static const struct file_operations pktgen_thread_fops = {
1859d50a6b56SStephen Hemminger 	.owner   = THIS_MODULE,
1860d50a6b56SStephen Hemminger 	.open    = pktgen_thread_open,
1861d50a6b56SStephen Hemminger 	.read    = seq_read,
1862d50a6b56SStephen Hemminger 	.llseek  = seq_lseek,
1863d50a6b56SStephen Hemminger 	.write   = pktgen_thread_write,
1864d50a6b56SStephen Hemminger 	.release = single_release,
1865d50a6b56SStephen Hemminger };
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds /* Think find or remove for NN */
18681da177e4SLinus Torvalds static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
18691da177e4SLinus Torvalds {
18701da177e4SLinus Torvalds 	struct pktgen_thread *t;
18711da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
18723e984840SEric Dumazet 	bool exact = (remove == FIND);
18731da177e4SLinus Torvalds 
1874cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list) {
18753e984840SEric Dumazet 		pkt_dev = pktgen_find_dev(t, ifname, exact);
18761da177e4SLinus Torvalds 		if (pkt_dev) {
18771da177e4SLinus Torvalds 			if (remove) {
18781da177e4SLinus Torvalds 				if_lock(t);
187995ed63f7SArthur Kepner 				pkt_dev->removal_mark = 1;
188095ed63f7SArthur Kepner 				t->control |= T_REMDEV;
18811da177e4SLinus Torvalds 				if_unlock(t);
18821da177e4SLinus Torvalds 			}
18831da177e4SLinus Torvalds 			break;
18841da177e4SLinus Torvalds 		}
18851da177e4SLinus Torvalds 	}
18861da177e4SLinus Torvalds 	return pkt_dev;
18871da177e4SLinus Torvalds }
18881da177e4SLinus Torvalds 
188995ed63f7SArthur Kepner /*
189095ed63f7SArthur Kepner  * mark a device for removal
189195ed63f7SArthur Kepner  */
189239df232fSStephen Hemminger static void pktgen_mark_device(const char *ifname)
18931da177e4SLinus Torvalds {
18941da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
189595ed63f7SArthur Kepner 	const int max_tries = 10, msec_per_try = 125;
189695ed63f7SArthur Kepner 	int i = 0;
189795ed63f7SArthur Kepner 
18986146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
1899f9467eaeSJoe Perches 	pr_debug("%s: marking %s for removal\n", __func__, ifname);
190095ed63f7SArthur Kepner 
190195ed63f7SArthur Kepner 	while (1) {
190295ed63f7SArthur Kepner 
190395ed63f7SArthur Kepner 		pkt_dev = __pktgen_NN_threads(ifname, REMOVE);
1904222f1806SLuiz Capitulino 		if (pkt_dev == NULL)
1905222f1806SLuiz Capitulino 			break;	/* success */
190695ed63f7SArthur Kepner 
19076146e6a4SLuiz Capitulino 		mutex_unlock(&pktgen_thread_lock);
1908f9467eaeSJoe Perches 		pr_debug("%s: waiting for %s to disappear....\n",
1909f9467eaeSJoe Perches 			 __func__, ifname);
191095ed63f7SArthur Kepner 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
19116146e6a4SLuiz Capitulino 		mutex_lock(&pktgen_thread_lock);
191295ed63f7SArthur Kepner 
191395ed63f7SArthur Kepner 		if (++i >= max_tries) {
1914f9467eaeSJoe Perches 			pr_err("%s: timed out after waiting %d msec for device %s to be removed\n",
1915f9467eaeSJoe Perches 			       __func__, msec_per_try * i, ifname);
191695ed63f7SArthur Kepner 			break;
191795ed63f7SArthur Kepner 		}
191895ed63f7SArthur Kepner 
191995ed63f7SArthur Kepner 	}
192095ed63f7SArthur Kepner 
19216146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
192239df232fSStephen Hemminger }
192395ed63f7SArthur Kepner 
192439df232fSStephen Hemminger static void pktgen_change_name(struct net_device *dev)
192539df232fSStephen Hemminger {
192639df232fSStephen Hemminger 	struct pktgen_thread *t;
192739df232fSStephen Hemminger 
192839df232fSStephen Hemminger 	list_for_each_entry(t, &pktgen_threads, th_list) {
192939df232fSStephen Hemminger 		struct pktgen_dev *pkt_dev;
193039df232fSStephen Hemminger 
193139df232fSStephen Hemminger 		list_for_each_entry(pkt_dev, &t->if_list, list) {
193239df232fSStephen Hemminger 			if (pkt_dev->odev != dev)
193339df232fSStephen Hemminger 				continue;
193439df232fSStephen Hemminger 
193539df232fSStephen Hemminger 			remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
193639df232fSStephen Hemminger 
19372975315bSAlexey Dobriyan 			pkt_dev->entry = proc_create_data(dev->name, 0600,
19382975315bSAlexey Dobriyan 							  pg_proc_dir,
19392975315bSAlexey Dobriyan 							  &pktgen_if_fops,
19402975315bSAlexey Dobriyan 							  pkt_dev);
194139df232fSStephen Hemminger 			if (!pkt_dev->entry)
1942f9467eaeSJoe Perches 				pr_err("can't move proc entry for '%s'\n",
1943f9467eaeSJoe Perches 				       dev->name);
194439df232fSStephen Hemminger 			break;
194539df232fSStephen Hemminger 		}
194639df232fSStephen Hemminger 	}
19471da177e4SLinus Torvalds }
19481da177e4SLinus Torvalds 
1949222f1806SLuiz Capitulino static int pktgen_device_event(struct notifier_block *unused,
1950222f1806SLuiz Capitulino 			       unsigned long event, void *ptr)
19511da177e4SLinus Torvalds {
195239df232fSStephen Hemminger 	struct net_device *dev = ptr;
19531da177e4SLinus Torvalds 
1954721499e8SYOSHIFUJI Hideaki 	if (!net_eq(dev_net(dev), &init_net))
1955e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
1956e9dc8653SEric W. Biederman 
19571da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
19581da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
19591da177e4SLinus Torvalds 	 */
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	switch (event) {
196239df232fSStephen Hemminger 	case NETDEV_CHANGENAME:
196339df232fSStephen Hemminger 		pktgen_change_name(dev);
19641da177e4SLinus Torvalds 		break;
19651da177e4SLinus Torvalds 
19661da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
196795ed63f7SArthur Kepner 		pktgen_mark_device(dev->name);
19681da177e4SLinus Torvalds 		break;
19693ff50b79SStephen Hemminger 	}
19701da177e4SLinus Torvalds 
19711da177e4SLinus Torvalds 	return NOTIFY_DONE;
19721da177e4SLinus Torvalds }
19731da177e4SLinus Torvalds 
197463adc6fbSStephen Hemminger static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev,
197563adc6fbSStephen Hemminger 						 const char *ifname)
1976e6fce5b9SRobert Olsson {
1977e6fce5b9SRobert Olsson 	char b[IFNAMSIZ+5];
1978*d6182223SPaul Gortmaker 	int i;
1979e6fce5b9SRobert Olsson 
1980e6fce5b9SRobert Olsson 	for (i = 0; ifname[i] != '@'; i++) {
1981e6fce5b9SRobert Olsson 		if (i == IFNAMSIZ)
1982e6fce5b9SRobert Olsson 			break;
1983e6fce5b9SRobert Olsson 
1984e6fce5b9SRobert Olsson 		b[i] = ifname[i];
1985e6fce5b9SRobert Olsson 	}
1986e6fce5b9SRobert Olsson 	b[i] = 0;
1987e6fce5b9SRobert Olsson 
1988e6fce5b9SRobert Olsson 	return dev_get_by_name(&init_net, b);
1989e6fce5b9SRobert Olsson }
1990e6fce5b9SRobert Olsson 
1991e6fce5b9SRobert Olsson 
19921da177e4SLinus Torvalds /* Associate pktgen_dev with a device. */
19931da177e4SLinus Torvalds 
199439df232fSStephen Hemminger static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
1995222f1806SLuiz Capitulino {
19961da177e4SLinus Torvalds 	struct net_device *odev;
199739df232fSStephen Hemminger 	int err;
19981da177e4SLinus Torvalds 
19991da177e4SLinus Torvalds 	/* Clean old setups */
20001da177e4SLinus Torvalds 	if (pkt_dev->odev) {
20011da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
20021da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
20031da177e4SLinus Torvalds 	}
20041da177e4SLinus Torvalds 
2005e6fce5b9SRobert Olsson 	odev = pktgen_dev_get_by_name(pkt_dev, ifname);
20061da177e4SLinus Torvalds 	if (!odev) {
2007f9467eaeSJoe Perches 		pr_err("no such netdevice: \"%s\"\n", ifname);
200839df232fSStephen Hemminger 		return -ENODEV;
20091da177e4SLinus Torvalds 	}
201039df232fSStephen Hemminger 
20111da177e4SLinus Torvalds 	if (odev->type != ARPHRD_ETHER) {
2012f9467eaeSJoe Perches 		pr_err("not an ethernet device: \"%s\"\n", ifname);
201339df232fSStephen Hemminger 		err = -EINVAL;
201439df232fSStephen Hemminger 	} else if (!netif_running(odev)) {
2015f9467eaeSJoe Perches 		pr_err("device is down: \"%s\"\n", ifname);
201639df232fSStephen Hemminger 		err = -ENETDOWN;
201739df232fSStephen Hemminger 	} else {
20181da177e4SLinus Torvalds 		pkt_dev->odev = odev;
201939df232fSStephen Hemminger 		return 0;
202039df232fSStephen Hemminger 	}
20211da177e4SLinus Torvalds 
20221da177e4SLinus Torvalds 	dev_put(odev);
202339df232fSStephen Hemminger 	return err;
20241da177e4SLinus Torvalds }
20251da177e4SLinus Torvalds 
20261da177e4SLinus Torvalds /* Read pkt_dev from the interface and set up internal pktgen_dev
20271da177e4SLinus Torvalds  * structure to have the right information to create/send packets
20281da177e4SLinus Torvalds  */
20291da177e4SLinus Torvalds static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
20301da177e4SLinus Torvalds {
203164c00d81SAndrew Gallatin 	int ntxq;
203264c00d81SAndrew Gallatin 
20331da177e4SLinus Torvalds 	if (!pkt_dev->odev) {
2034f9467eaeSJoe Perches 		pr_err("ERROR: pkt_dev->odev == NULL in setup_inject\n");
2035222f1806SLuiz Capitulino 		sprintf(pkt_dev->result,
2036222f1806SLuiz Capitulino 			"ERROR: pkt_dev->odev == NULL in setup_inject.\n");
20371da177e4SLinus Torvalds 		return;
20381da177e4SLinus Torvalds 	}
20391da177e4SLinus Torvalds 
204064c00d81SAndrew Gallatin 	/* make sure that we don't pick a non-existing transmit queue */
204164c00d81SAndrew Gallatin 	ntxq = pkt_dev->odev->real_num_tx_queues;
2042bfdbc0acSRobert Olsson 
204364c00d81SAndrew Gallatin 	if (ntxq <= pkt_dev->queue_map_min) {
2044f9467eaeSJoe Perches 		pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
204588271660SJesse Brandeburg 			   pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
2046593f63b0SEric Dumazet 			   pkt_dev->odevname);
204764c00d81SAndrew Gallatin 		pkt_dev->queue_map_min = ntxq - 1;
204864c00d81SAndrew Gallatin 	}
204988271660SJesse Brandeburg 	if (pkt_dev->queue_map_max >= ntxq) {
2050f9467eaeSJoe Perches 		pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
205188271660SJesse Brandeburg 			   pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
2052593f63b0SEric Dumazet 			   pkt_dev->odevname);
205364c00d81SAndrew Gallatin 		pkt_dev->queue_map_max = ntxq - 1;
205464c00d81SAndrew Gallatin 	}
205564c00d81SAndrew Gallatin 
20561da177e4SLinus Torvalds 	/* Default to the interface's mac if not explicitly set. */
20571da177e4SLinus Torvalds 
2058f404e9a6SKris Katterjohn 	if (is_zero_ether_addr(pkt_dev->src_mac))
2059f404e9a6SKris Katterjohn 		memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN);
20601da177e4SLinus Torvalds 
20611da177e4SLinus Torvalds 	/* Set up Dest MAC */
2062f404e9a6SKris Katterjohn 	memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN);
20631da177e4SLinus Torvalds 
20641da177e4SLinus Torvalds 	/* Set up pkt size */
20651da177e4SLinus Torvalds 	pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size;
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6) {
20681da177e4SLinus Torvalds 		/*
20691da177e4SLinus Torvalds 		 * Skip this automatic address setting until locks or functions
20701da177e4SLinus Torvalds 		 * gets exported
20711da177e4SLinus Torvalds 		 */
20721da177e4SLinus Torvalds 
20731da177e4SLinus Torvalds #ifdef NOTNOW
20741da177e4SLinus Torvalds 		int i, set = 0, err = 1;
20751da177e4SLinus Torvalds 		struct inet6_dev *idev;
20761da177e4SLinus Torvalds 
20771da177e4SLinus Torvalds 		for (i = 0; i < IN6_ADDR_HSIZE; i++)
20781da177e4SLinus Torvalds 			if (pkt_dev->cur_in6_saddr.s6_addr[i]) {
20791da177e4SLinus Torvalds 				set = 1;
20801da177e4SLinus Torvalds 				break;
20811da177e4SLinus Torvalds 			}
20821da177e4SLinus Torvalds 
20831da177e4SLinus Torvalds 		if (!set) {
20841da177e4SLinus Torvalds 
20851da177e4SLinus Torvalds 			/*
20861da177e4SLinus Torvalds 			 * Use linklevel address if unconfigured.
20871da177e4SLinus Torvalds 			 *
20881da177e4SLinus Torvalds 			 * use ipv6_get_lladdr if/when it's get exported
20891da177e4SLinus Torvalds 			 */
20901da177e4SLinus Torvalds 
20918814c4b5SYOSHIFUJI Hideaki 			rcu_read_lock();
209263adc6fbSStephen Hemminger 			idev = __in6_dev_get(pkt_dev->odev);
209363adc6fbSStephen Hemminger 			if (idev) {
20941da177e4SLinus Torvalds 				struct inet6_ifaddr *ifp;
20951da177e4SLinus Torvalds 
20961da177e4SLinus Torvalds 				read_lock_bh(&idev->lock);
2097222f1806SLuiz Capitulino 				for (ifp = idev->addr_list; ifp;
2098222f1806SLuiz Capitulino 				     ifp = ifp->if_next) {
2099f64f9e71SJoe Perches 					if (ifp->scope == IFA_LINK &&
2100f64f9e71SJoe Perches 					    !(ifp->flags & IFA_F_TENTATIVE)) {
2101222f1806SLuiz Capitulino 						ipv6_addr_copy(&pkt_dev->
2102222f1806SLuiz Capitulino 							       cur_in6_saddr,
2103222f1806SLuiz Capitulino 							       &ifp->addr);
21041da177e4SLinus Torvalds 						err = 0;
21051da177e4SLinus Torvalds 						break;
21061da177e4SLinus Torvalds 					}
21071da177e4SLinus Torvalds 				}
21081da177e4SLinus Torvalds 				read_unlock_bh(&idev->lock);
21091da177e4SLinus Torvalds 			}
21108814c4b5SYOSHIFUJI Hideaki 			rcu_read_unlock();
2111222f1806SLuiz Capitulino 			if (err)
2112f9467eaeSJoe Perches 				pr_err("ERROR: IPv6 link address not available\n");
21131da177e4SLinus Torvalds 		}
21141da177e4SLinus Torvalds #endif
2115222f1806SLuiz Capitulino 	} else {
21161da177e4SLinus Torvalds 		pkt_dev->saddr_min = 0;
21171da177e4SLinus Torvalds 		pkt_dev->saddr_max = 0;
21181da177e4SLinus Torvalds 		if (strlen(pkt_dev->src_min) == 0) {
21191da177e4SLinus Torvalds 
21201da177e4SLinus Torvalds 			struct in_device *in_dev;
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds 			rcu_read_lock();
2123e5ed6399SHerbert Xu 			in_dev = __in_dev_get_rcu(pkt_dev->odev);
21241da177e4SLinus Torvalds 			if (in_dev) {
21251da177e4SLinus Torvalds 				if (in_dev->ifa_list) {
2126222f1806SLuiz Capitulino 					pkt_dev->saddr_min =
2127222f1806SLuiz Capitulino 					    in_dev->ifa_list->ifa_address;
21281da177e4SLinus Torvalds 					pkt_dev->saddr_max = pkt_dev->saddr_min;
21291da177e4SLinus Torvalds 				}
21301da177e4SLinus Torvalds 			}
21311da177e4SLinus Torvalds 			rcu_read_unlock();
2132222f1806SLuiz Capitulino 		} else {
21331da177e4SLinus Torvalds 			pkt_dev->saddr_min = in_aton(pkt_dev->src_min);
21341da177e4SLinus Torvalds 			pkt_dev->saddr_max = in_aton(pkt_dev->src_max);
21351da177e4SLinus Torvalds 		}
21361da177e4SLinus Torvalds 
21371da177e4SLinus Torvalds 		pkt_dev->daddr_min = in_aton(pkt_dev->dst_min);
21381da177e4SLinus Torvalds 		pkt_dev->daddr_max = in_aton(pkt_dev->dst_max);
21391da177e4SLinus Torvalds 	}
21401da177e4SLinus Torvalds 	/* Initialize current values. */
21411da177e4SLinus Torvalds 	pkt_dev->cur_dst_mac_offset = 0;
21421da177e4SLinus Torvalds 	pkt_dev->cur_src_mac_offset = 0;
21431da177e4SLinus Torvalds 	pkt_dev->cur_saddr = pkt_dev->saddr_min;
21441da177e4SLinus Torvalds 	pkt_dev->cur_daddr = pkt_dev->daddr_min;
21451da177e4SLinus Torvalds 	pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
21461da177e4SLinus Torvalds 	pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
21471da177e4SLinus Torvalds 	pkt_dev->nflows = 0;
21481da177e4SLinus Torvalds }
21491da177e4SLinus Torvalds 
21501da177e4SLinus Torvalds 
2151fd29cf72SStephen Hemminger static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
2152fd29cf72SStephen Hemminger {
2153ef87979cSStephen Hemminger 	ktime_t start_time, end_time;
2154417bc4b8SEric Dumazet 	s64 remaining;
21552bc481cfSStephen Hemminger 	struct hrtimer_sleeper t;
2156fd29cf72SStephen Hemminger 
21572bc481cfSStephen Hemminger 	hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
21582bc481cfSStephen Hemminger 	hrtimer_set_expires(&t.timer, spin_until);
2159fd29cf72SStephen Hemminger 
216043d28b65SDaniel Turull 	remaining = ktime_to_ns(hrtimer_expires_remaining(&t.timer));
2161417bc4b8SEric Dumazet 	if (remaining <= 0) {
2162417bc4b8SEric Dumazet 		pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
21631da177e4SLinus Torvalds 		return;
2164417bc4b8SEric Dumazet 	}
21652bc481cfSStephen Hemminger 
2166ef87979cSStephen Hemminger 	start_time = ktime_now();
216743d28b65SDaniel Turull 	if (remaining < 100000)
216843d28b65SDaniel Turull 		ndelay(remaining);	/* really small just spin */
21692bc481cfSStephen Hemminger 	else {
21702bc481cfSStephen Hemminger 		/* see do_nanosleep */
21712bc481cfSStephen Hemminger 		hrtimer_init_sleeper(&t, current);
21722bc481cfSStephen Hemminger 		do {
21732bc481cfSStephen Hemminger 			set_current_state(TASK_INTERRUPTIBLE);
21742bc481cfSStephen Hemminger 			hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
21752bc481cfSStephen Hemminger 			if (!hrtimer_active(&t.timer))
21762bc481cfSStephen Hemminger 				t.task = NULL;
21772bc481cfSStephen Hemminger 
21782bc481cfSStephen Hemminger 			if (likely(t.task))
21791da177e4SLinus Torvalds 				schedule();
21801da177e4SLinus Torvalds 
21812bc481cfSStephen Hemminger 			hrtimer_cancel(&t.timer);
21822bc481cfSStephen Hemminger 		} while (t.task && pkt_dev->running && !signal_pending(current));
21832bc481cfSStephen Hemminger 		__set_current_state(TASK_RUNNING);
21841da177e4SLinus Torvalds 	}
2185ef87979cSStephen Hemminger 	end_time = ktime_now();
2186ef87979cSStephen Hemminger 
2187ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time));
218807a0f0f0SDaniel Turull 	pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay);
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
219116dab72fSJamal Hadi Salim static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
219216dab72fSJamal Hadi Salim {
2193a553e4a6SJamal Hadi Salim 	pkt_dev->pkt_overhead = 0;
219416dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
219516dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
219616dab72fSJamal Hadi Salim 	pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
219716dab72fSJamal Hadi Salim }
219816dab72fSJamal Hadi Salim 
2199648fda74SStephen Hemminger static inline int f_seen(const struct pktgen_dev *pkt_dev, int flow)
2200007a531bSJamal Hadi Salim {
2201648fda74SStephen Hemminger 	return !!(pkt_dev->flows[flow].flags & F_INIT);
2202007a531bSJamal Hadi Salim }
2203007a531bSJamal Hadi Salim 
2204007a531bSJamal Hadi Salim static inline int f_pick(struct pktgen_dev *pkt_dev)
2205007a531bSJamal Hadi Salim {
2206007a531bSJamal Hadi Salim 	int flow = pkt_dev->curfl;
2207007a531bSJamal Hadi Salim 
2208007a531bSJamal Hadi Salim 	if (pkt_dev->flags & F_FLOW_SEQ) {
2209007a531bSJamal Hadi Salim 		if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
2210007a531bSJamal Hadi Salim 			/* reset time */
2211007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22121211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
2213007a531bSJamal Hadi Salim 			pkt_dev->curfl += 1;
2214007a531bSJamal Hadi Salim 			if (pkt_dev->curfl >= pkt_dev->cflows)
2215007a531bSJamal Hadi Salim 				pkt_dev->curfl = 0; /*reset */
2216007a531bSJamal Hadi Salim 		}
2217007a531bSJamal Hadi Salim 	} else {
2218007a531bSJamal Hadi Salim 		flow = random32() % pkt_dev->cflows;
22191211a645SRobert Olsson 		pkt_dev->curfl = flow;
2220007a531bSJamal Hadi Salim 
22211211a645SRobert Olsson 		if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
2222007a531bSJamal Hadi Salim 			pkt_dev->flows[flow].count = 0;
22231211a645SRobert Olsson 			pkt_dev->flows[flow].flags = 0;
22241211a645SRobert Olsson 		}
2225007a531bSJamal Hadi Salim 	}
2226007a531bSJamal Hadi Salim 
2227007a531bSJamal Hadi Salim 	return pkt_dev->curfl;
2228007a531bSJamal Hadi Salim }
2229007a531bSJamal Hadi Salim 
2230a553e4a6SJamal Hadi Salim 
2231a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2232a553e4a6SJamal Hadi Salim /* If there was already an IPSEC SA, we keep it as is, else
2233a553e4a6SJamal Hadi Salim  * we go look for it ...
2234a553e4a6SJamal Hadi Salim */
2235bd55775cSJamal Hadi Salim #define DUMMY_MARK 0
2236fea1ab0fSAdrian Bunk static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
2237a553e4a6SJamal Hadi Salim {
2238a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[flow].x;
2239a553e4a6SJamal Hadi Salim 	if (!x) {
2240a553e4a6SJamal Hadi Salim 		/*slow path: we dont already have xfrm_state*/
2241bd55775cSJamal Hadi Salim 		x = xfrm_stateonly_find(&init_net, DUMMY_MARK,
22425447c5e4SAlexey Dobriyan 					(xfrm_address_t *)&pkt_dev->cur_daddr,
2243a553e4a6SJamal Hadi Salim 					(xfrm_address_t *)&pkt_dev->cur_saddr,
2244a553e4a6SJamal Hadi Salim 					AF_INET,
2245a553e4a6SJamal Hadi Salim 					pkt_dev->ipsmode,
2246a553e4a6SJamal Hadi Salim 					pkt_dev->ipsproto, 0);
2247a553e4a6SJamal Hadi Salim 		if (x) {
2248a553e4a6SJamal Hadi Salim 			pkt_dev->flows[flow].x = x;
2249a553e4a6SJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
2250a553e4a6SJamal Hadi Salim 			pkt_dev->pkt_overhead += x->props.header_len;
2251a553e4a6SJamal Hadi Salim 		}
2252a553e4a6SJamal Hadi Salim 
2253a553e4a6SJamal Hadi Salim 	}
2254a553e4a6SJamal Hadi Salim }
2255a553e4a6SJamal Hadi Salim #endif
2256fd2ea0a7SDavid S. Miller static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
2257fd2ea0a7SDavid S. Miller {
2258e6fce5b9SRobert Olsson 
2259e6fce5b9SRobert Olsson 	if (pkt_dev->flags & F_QUEUE_MAP_CPU)
2260e6fce5b9SRobert Olsson 		pkt_dev->cur_queue_map = smp_processor_id();
2261e6fce5b9SRobert Olsson 
2262896a7cf8SEric Dumazet 	else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
2263fd2ea0a7SDavid S. Miller 		__u16 t;
2264fd2ea0a7SDavid S. Miller 		if (pkt_dev->flags & F_QUEUE_MAP_RND) {
2265fd2ea0a7SDavid S. Miller 			t = random32() %
2266fd2ea0a7SDavid S. Miller 				(pkt_dev->queue_map_max -
2267fd2ea0a7SDavid S. Miller 				 pkt_dev->queue_map_min + 1)
2268fd2ea0a7SDavid S. Miller 				+ pkt_dev->queue_map_min;
2269fd2ea0a7SDavid S. Miller 		} else {
2270fd2ea0a7SDavid S. Miller 			t = pkt_dev->cur_queue_map + 1;
2271fd2ea0a7SDavid S. Miller 			if (t > pkt_dev->queue_map_max)
2272fd2ea0a7SDavid S. Miller 				t = pkt_dev->queue_map_min;
2273fd2ea0a7SDavid S. Miller 		}
2274fd2ea0a7SDavid S. Miller 		pkt_dev->cur_queue_map = t;
2275fd2ea0a7SDavid S. Miller 	}
2276bfdbc0acSRobert Olsson 	pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
2277fd2ea0a7SDavid S. Miller }
2278fd2ea0a7SDavid S. Miller 
22791da177e4SLinus Torvalds /* Increment/randomize headers according to flags and current values
22801da177e4SLinus Torvalds  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
22811da177e4SLinus Torvalds  */
2282222f1806SLuiz Capitulino static void mod_cur_headers(struct pktgen_dev *pkt_dev)
2283222f1806SLuiz Capitulino {
22841da177e4SLinus Torvalds 	__u32 imn;
22851da177e4SLinus Torvalds 	__u32 imx;
22861da177e4SLinus Torvalds 	int flow = 0;
22871da177e4SLinus Torvalds 
2288007a531bSJamal Hadi Salim 	if (pkt_dev->cflows)
2289007a531bSJamal Hadi Salim 		flow = f_pick(pkt_dev);
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds 	/*  Deal with source MAC */
22921da177e4SLinus Torvalds 	if (pkt_dev->src_mac_count > 1) {
22931da177e4SLinus Torvalds 		__u32 mc;
22941da177e4SLinus Torvalds 		__u32 tmp;
22951da177e4SLinus Torvalds 
22961da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACSRC_RND)
22975fa6fc76SStephen Hemminger 			mc = random32() % pkt_dev->src_mac_count;
22981da177e4SLinus Torvalds 		else {
22991da177e4SLinus Torvalds 			mc = pkt_dev->cur_src_mac_offset++;
2300ff2a79a5SRobert Olsson 			if (pkt_dev->cur_src_mac_offset >=
2301222f1806SLuiz Capitulino 			    pkt_dev->src_mac_count)
23021da177e4SLinus Torvalds 				pkt_dev->cur_src_mac_offset = 0;
23031da177e4SLinus Torvalds 		}
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 		tmp = pkt_dev->src_mac[5] + (mc & 0xFF);
23061da177e4SLinus Torvalds 		pkt_dev->hh[11] = tmp;
23071da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23081da177e4SLinus Torvalds 		pkt_dev->hh[10] = tmp;
23091da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23101da177e4SLinus Torvalds 		pkt_dev->hh[9] = tmp;
23111da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23121da177e4SLinus Torvalds 		pkt_dev->hh[8] = tmp;
23131da177e4SLinus Torvalds 		tmp = (pkt_dev->src_mac[1] + (tmp >> 8));
23141da177e4SLinus Torvalds 		pkt_dev->hh[7] = tmp;
23151da177e4SLinus Torvalds 	}
23161da177e4SLinus Torvalds 
23171da177e4SLinus Torvalds 	/*  Deal with Destination MAC */
23181da177e4SLinus Torvalds 	if (pkt_dev->dst_mac_count > 1) {
23191da177e4SLinus Torvalds 		__u32 mc;
23201da177e4SLinus Torvalds 		__u32 tmp;
23211da177e4SLinus Torvalds 
23221da177e4SLinus Torvalds 		if (pkt_dev->flags & F_MACDST_RND)
23235fa6fc76SStephen Hemminger 			mc = random32() % pkt_dev->dst_mac_count;
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 		else {
23261da177e4SLinus Torvalds 			mc = pkt_dev->cur_dst_mac_offset++;
2327ff2a79a5SRobert Olsson 			if (pkt_dev->cur_dst_mac_offset >=
2328222f1806SLuiz Capitulino 			    pkt_dev->dst_mac_count) {
23291da177e4SLinus Torvalds 				pkt_dev->cur_dst_mac_offset = 0;
23301da177e4SLinus Torvalds 			}
23311da177e4SLinus Torvalds 		}
23321da177e4SLinus Torvalds 
23331da177e4SLinus Torvalds 		tmp = pkt_dev->dst_mac[5] + (mc & 0xFF);
23341da177e4SLinus Torvalds 		pkt_dev->hh[5] = tmp;
23351da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
23361da177e4SLinus Torvalds 		pkt_dev->hh[4] = tmp;
23371da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
23381da177e4SLinus Torvalds 		pkt_dev->hh[3] = tmp;
23391da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
23401da177e4SLinus Torvalds 		pkt_dev->hh[2] = tmp;
23411da177e4SLinus Torvalds 		tmp = (pkt_dev->dst_mac[1] + (tmp >> 8));
23421da177e4SLinus Torvalds 		pkt_dev->hh[1] = tmp;
23431da177e4SLinus Torvalds 	}
23441da177e4SLinus Torvalds 
2345ca6549afSSteven Whitehouse 	if (pkt_dev->flags & F_MPLS_RND) {
2346ca6549afSSteven Whitehouse 		unsigned i;
2347ca6549afSSteven Whitehouse 		for (i = 0; i < pkt_dev->nr_labels; i++)
2348ca6549afSSteven Whitehouse 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
2349ca6549afSSteven Whitehouse 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
23505fa6fc76SStephen Hemminger 					     ((__force __be32)random32() &
2351ca6549afSSteven Whitehouse 						      htonl(0x000fffff));
2352ca6549afSSteven Whitehouse 	}
2353ca6549afSSteven Whitehouse 
235434954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
23555fa6fc76SStephen Hemminger 		pkt_dev->vlan_id = random32() & (4096-1);
235634954ddcSFrancesco Fondelli 	}
235734954ddcSFrancesco Fondelli 
235834954ddcSFrancesco Fondelli 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
23595fa6fc76SStephen Hemminger 		pkt_dev->svlan_id = random32() & (4096 - 1);
236034954ddcSFrancesco Fondelli 	}
236134954ddcSFrancesco Fondelli 
23621da177e4SLinus Torvalds 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
23631da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPSRC_RND)
23645fa6fc76SStephen Hemminger 			pkt_dev->cur_udp_src = random32() %
23655fa6fc76SStephen Hemminger 				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
23665fa6fc76SStephen Hemminger 				+ pkt_dev->udp_src_min;
23671da177e4SLinus Torvalds 
23681da177e4SLinus Torvalds 		else {
23691da177e4SLinus Torvalds 			pkt_dev->cur_udp_src++;
23701da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max)
23711da177e4SLinus Torvalds 				pkt_dev->cur_udp_src = pkt_dev->udp_src_min;
23721da177e4SLinus Torvalds 		}
23731da177e4SLinus Torvalds 	}
23741da177e4SLinus Torvalds 
23751da177e4SLinus Torvalds 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
23761da177e4SLinus Torvalds 		if (pkt_dev->flags & F_UDPDST_RND) {
23775fa6fc76SStephen Hemminger 			pkt_dev->cur_udp_dst = random32() %
23785fa6fc76SStephen Hemminger 				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
23795fa6fc76SStephen Hemminger 				+ pkt_dev->udp_dst_min;
2380222f1806SLuiz Capitulino 		} else {
23811da177e4SLinus Torvalds 			pkt_dev->cur_udp_dst++;
23821da177e4SLinus Torvalds 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
23831da177e4SLinus Torvalds 				pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min;
23841da177e4SLinus Torvalds 		}
23851da177e4SLinus Torvalds 	}
23861da177e4SLinus Torvalds 
23871da177e4SLinus Torvalds 	if (!(pkt_dev->flags & F_IPV6)) {
23881da177e4SLinus Torvalds 
238963adc6fbSStephen Hemminger 		imn = ntohl(pkt_dev->saddr_min);
239063adc6fbSStephen Hemminger 		imx = ntohl(pkt_dev->saddr_max);
239163adc6fbSStephen Hemminger 		if (imn < imx) {
23921da177e4SLinus Torvalds 			__u32 t;
23931da177e4SLinus Torvalds 			if (pkt_dev->flags & F_IPSRC_RND)
23945fa6fc76SStephen Hemminger 				t = random32() % (imx - imn) + imn;
23951da177e4SLinus Torvalds 			else {
23961da177e4SLinus Torvalds 				t = ntohl(pkt_dev->cur_saddr);
23971da177e4SLinus Torvalds 				t++;
239863adc6fbSStephen Hemminger 				if (t > imx)
23991da177e4SLinus Torvalds 					t = imn;
240063adc6fbSStephen Hemminger 
24011da177e4SLinus Torvalds 			}
24021da177e4SLinus Torvalds 			pkt_dev->cur_saddr = htonl(t);
24031da177e4SLinus Torvalds 		}
24041da177e4SLinus Torvalds 
2405007a531bSJamal Hadi Salim 		if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
24061da177e4SLinus Torvalds 			pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
24071da177e4SLinus Torvalds 		} else {
2408252e3346SAl Viro 			imn = ntohl(pkt_dev->daddr_min);
2409252e3346SAl Viro 			imx = ntohl(pkt_dev->daddr_max);
2410252e3346SAl Viro 			if (imn < imx) {
24111da177e4SLinus Torvalds 				__u32 t;
2412252e3346SAl Viro 				__be32 s;
24131da177e4SLinus Torvalds 				if (pkt_dev->flags & F_IPDST_RND) {
24141da177e4SLinus Torvalds 
24155fa6fc76SStephen Hemminger 					t = random32() % (imx - imn) + imn;
2416252e3346SAl Viro 					s = htonl(t);
24171da177e4SLinus Torvalds 
241821cf2253SJoe Perches 					while (ipv4_is_loopback(s) ||
241921cf2253SJoe Perches 					       ipv4_is_multicast(s) ||
24201e637c74SJan Engelhardt 					       ipv4_is_lbcast(s) ||
242121cf2253SJoe Perches 					       ipv4_is_zeronet(s) ||
242221cf2253SJoe Perches 					       ipv4_is_local_multicast(s)) {
24235fa6fc76SStephen Hemminger 						t = random32() % (imx - imn) + imn;
2424252e3346SAl Viro 						s = htonl(t);
24251da177e4SLinus Torvalds 					}
2426252e3346SAl Viro 					pkt_dev->cur_daddr = s;
2427252e3346SAl Viro 				} else {
24281da177e4SLinus Torvalds 					t = ntohl(pkt_dev->cur_daddr);
24291da177e4SLinus Torvalds 					t++;
24301da177e4SLinus Torvalds 					if (t > imx) {
24311da177e4SLinus Torvalds 						t = imn;
24321da177e4SLinus Torvalds 					}
24331da177e4SLinus Torvalds 					pkt_dev->cur_daddr = htonl(t);
24341da177e4SLinus Torvalds 				}
24351da177e4SLinus Torvalds 			}
24361da177e4SLinus Torvalds 			if (pkt_dev->cflows) {
2437007a531bSJamal Hadi Salim 				pkt_dev->flows[flow].flags |= F_INIT;
2438222f1806SLuiz Capitulino 				pkt_dev->flows[flow].cur_daddr =
2439222f1806SLuiz Capitulino 				    pkt_dev->cur_daddr;
2440a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2441a553e4a6SJamal Hadi Salim 				if (pkt_dev->flags & F_IPSEC_ON)
2442a553e4a6SJamal Hadi Salim 					get_ipsec_sa(pkt_dev, flow);
2443a553e4a6SJamal Hadi Salim #endif
24441da177e4SLinus Torvalds 				pkt_dev->nflows++;
24451da177e4SLinus Torvalds 			}
24461da177e4SLinus Torvalds 		}
2447222f1806SLuiz Capitulino 	} else {		/* IPV6 * */
2448222f1806SLuiz Capitulino 
24491da177e4SLinus Torvalds 		if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 &&
24501da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[1] == 0 &&
24511da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[2] == 0 &&
24521da177e4SLinus Torvalds 		    pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ;
24531da177e4SLinus Torvalds 		else {
24541da177e4SLinus Torvalds 			int i;
24551da177e4SLinus Torvalds 
24561da177e4SLinus Torvalds 			/* Only random destinations yet */
24571da177e4SLinus Torvalds 
24581da177e4SLinus Torvalds 			for (i = 0; i < 4; i++) {
24591da177e4SLinus Torvalds 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
24605fa6fc76SStephen Hemminger 				    (((__force __be32)random32() |
24611da177e4SLinus Torvalds 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
24621da177e4SLinus Torvalds 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
24631da177e4SLinus Torvalds 			}
24641da177e4SLinus Torvalds 		}
24651da177e4SLinus Torvalds 	}
24661da177e4SLinus Torvalds 
24671da177e4SLinus Torvalds 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
24681da177e4SLinus Torvalds 		__u32 t;
24691da177e4SLinus Torvalds 		if (pkt_dev->flags & F_TXSIZE_RND) {
24705fa6fc76SStephen Hemminger 			t = random32() %
24715fa6fc76SStephen Hemminger 				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
24725fa6fc76SStephen Hemminger 				+ pkt_dev->min_pkt_size;
2473222f1806SLuiz Capitulino 		} else {
24741da177e4SLinus Torvalds 			t = pkt_dev->cur_pkt_size + 1;
24751da177e4SLinus Torvalds 			if (t > pkt_dev->max_pkt_size)
24761da177e4SLinus Torvalds 				t = pkt_dev->min_pkt_size;
24771da177e4SLinus Torvalds 		}
24781da177e4SLinus Torvalds 		pkt_dev->cur_pkt_size = t;
24791da177e4SLinus Torvalds 	}
24801da177e4SLinus Torvalds 
2481fd2ea0a7SDavid S. Miller 	set_cur_queue_map(pkt_dev);
248245b270f8SRobert Olsson 
24831da177e4SLinus Torvalds 	pkt_dev->flows[flow].count++;
24841da177e4SLinus Torvalds }
24851da177e4SLinus Torvalds 
2486a553e4a6SJamal Hadi Salim 
2487a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2488a553e4a6SJamal Hadi Salim static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
2489a553e4a6SJamal Hadi Salim {
2490a553e4a6SJamal Hadi Salim 	struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2491a553e4a6SJamal Hadi Salim 	int err = 0;
2492a553e4a6SJamal Hadi Salim 	struct iphdr *iph;
2493a553e4a6SJamal Hadi Salim 
2494a553e4a6SJamal Hadi Salim 	if (!x)
2495a553e4a6SJamal Hadi Salim 		return 0;
2496a553e4a6SJamal Hadi Salim 	/* XXX: we dont support tunnel mode for now until
2497a553e4a6SJamal Hadi Salim 	 * we resolve the dst issue */
2498a553e4a6SJamal Hadi Salim 	if (x->props.mode != XFRM_MODE_TRANSPORT)
2499a553e4a6SJamal Hadi Salim 		return 0;
2500a553e4a6SJamal Hadi Salim 
2501a553e4a6SJamal Hadi Salim 	spin_lock(&x->lock);
2502a553e4a6SJamal Hadi Salim 	iph = ip_hdr(skb);
2503a553e4a6SJamal Hadi Salim 
250413996378SHerbert Xu 	err = x->outer_mode->output(x, skb);
2505a553e4a6SJamal Hadi Salim 	if (err)
2506a553e4a6SJamal Hadi Salim 		goto error;
2507a553e4a6SJamal Hadi Salim 	err = x->type->output(x, skb);
2508a553e4a6SJamal Hadi Salim 	if (err)
2509a553e4a6SJamal Hadi Salim 		goto error;
2510a553e4a6SJamal Hadi Salim 
2511a553e4a6SJamal Hadi Salim 	x->curlft.bytes += skb->len;
2512a553e4a6SJamal Hadi Salim 	x->curlft.packets++;
2513a553e4a6SJamal Hadi Salim error:
2514a553e4a6SJamal Hadi Salim 	spin_unlock(&x->lock);
2515a553e4a6SJamal Hadi Salim 	return err;
2516a553e4a6SJamal Hadi Salim }
2517a553e4a6SJamal Hadi Salim 
2518475ac1e4SStephen Hemminger static void free_SAs(struct pktgen_dev *pkt_dev)
2519a553e4a6SJamal Hadi Salim {
2520a553e4a6SJamal Hadi Salim 	if (pkt_dev->cflows) {
2521a553e4a6SJamal Hadi Salim 		/* let go of the SAs if we have them */
2522*d6182223SPaul Gortmaker 		int i;
2523*d6182223SPaul Gortmaker 		for (i = 0; i < pkt_dev->cflows; i++) {
2524a553e4a6SJamal Hadi Salim 			struct xfrm_state *x = pkt_dev->flows[i].x;
2525a553e4a6SJamal Hadi Salim 			if (x) {
2526a553e4a6SJamal Hadi Salim 				xfrm_state_put(x);
2527a553e4a6SJamal Hadi Salim 				pkt_dev->flows[i].x = NULL;
2528a553e4a6SJamal Hadi Salim 			}
2529a553e4a6SJamal Hadi Salim 		}
2530a553e4a6SJamal Hadi Salim 	}
2531a553e4a6SJamal Hadi Salim }
2532a553e4a6SJamal Hadi Salim 
2533475ac1e4SStephen Hemminger static int process_ipsec(struct pktgen_dev *pkt_dev,
2534a553e4a6SJamal Hadi Salim 			      struct sk_buff *skb, __be16 protocol)
2535a553e4a6SJamal Hadi Salim {
2536a553e4a6SJamal Hadi Salim 	if (pkt_dev->flags & F_IPSEC_ON) {
2537a553e4a6SJamal Hadi Salim 		struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
2538a553e4a6SJamal Hadi Salim 		int nhead = 0;
2539a553e4a6SJamal Hadi Salim 		if (x) {
2540a553e4a6SJamal Hadi Salim 			int ret;
2541a553e4a6SJamal Hadi Salim 			__u8 *eth;
2542a553e4a6SJamal Hadi Salim 			nhead = x->props.header_len - skb_headroom(skb);
2543a553e4a6SJamal Hadi Salim 			if (nhead > 0) {
2544a553e4a6SJamal Hadi Salim 				ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
2545a553e4a6SJamal Hadi Salim 				if (ret < 0) {
2546f9467eaeSJoe Perches 					pr_err("Error expanding ipsec packet %d\n",
2547f9467eaeSJoe Perches 					       ret);
2548b4bb4ac8SIlpo Järvinen 					goto err;
2549a553e4a6SJamal Hadi Salim 				}
2550a553e4a6SJamal Hadi Salim 			}
2551a553e4a6SJamal Hadi Salim 
2552a553e4a6SJamal Hadi Salim 			/* ipsec is not expecting ll header */
2553a553e4a6SJamal Hadi Salim 			skb_pull(skb, ETH_HLEN);
2554a553e4a6SJamal Hadi Salim 			ret = pktgen_output_ipsec(skb, pkt_dev);
2555a553e4a6SJamal Hadi Salim 			if (ret) {
2556f9467eaeSJoe Perches 				pr_err("Error creating ipsec packet %d\n", ret);
2557b4bb4ac8SIlpo Järvinen 				goto err;
2558a553e4a6SJamal Hadi Salim 			}
2559a553e4a6SJamal Hadi Salim 			/* restore ll */
2560a553e4a6SJamal Hadi Salim 			eth = (__u8 *) skb_push(skb, ETH_HLEN);
2561a553e4a6SJamal Hadi Salim 			memcpy(eth, pkt_dev->hh, 12);
2562a553e4a6SJamal Hadi Salim 			*(u16 *) &eth[12] = protocol;
2563a553e4a6SJamal Hadi Salim 		}
2564a553e4a6SJamal Hadi Salim 	}
2565a553e4a6SJamal Hadi Salim 	return 1;
2566b4bb4ac8SIlpo Järvinen err:
2567b4bb4ac8SIlpo Järvinen 	kfree_skb(skb);
2568b4bb4ac8SIlpo Järvinen 	return 0;
2569a553e4a6SJamal Hadi Salim }
2570a553e4a6SJamal Hadi Salim #endif
2571a553e4a6SJamal Hadi Salim 
2572ca6549afSSteven Whitehouse static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
2573ca6549afSSteven Whitehouse {
2574ca6549afSSteven Whitehouse 	unsigned i;
257563adc6fbSStephen Hemminger 	for (i = 0; i < pkt_dev->nr_labels; i++)
2576ca6549afSSteven Whitehouse 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
257763adc6fbSStephen Hemminger 
2578ca6549afSSteven Whitehouse 	mpls--;
2579ca6549afSSteven Whitehouse 	*mpls |= MPLS_STACK_BOTTOM;
2580ca6549afSSteven Whitehouse }
2581ca6549afSSteven Whitehouse 
25820f37c605SAl Viro static inline __be16 build_tci(unsigned int id, unsigned int cfi,
25830f37c605SAl Viro 			       unsigned int prio)
25840f37c605SAl Viro {
25850f37c605SAl Viro 	return htons(id | (cfi << 12) | (prio << 13));
25860f37c605SAl Viro }
25870f37c605SAl Viro 
25881da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
25891da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
25901da177e4SLinus Torvalds {
25911da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
25921da177e4SLinus Torvalds 	__u8 *eth;
25931da177e4SLinus Torvalds 	struct udphdr *udph;
25941da177e4SLinus Torvalds 	int datalen, iplen;
25951da177e4SLinus Torvalds 	struct iphdr *iph;
25961da177e4SLinus Torvalds 	struct pktgen_hdr *pgh = NULL;
2597d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IP);
2598ca6549afSSteven Whitehouse 	__be32 *mpls;
259934954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
260034954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
260134954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
260234954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2603fd2ea0a7SDavid S. Miller 	u16 queue_map;
2604ca6549afSSteven Whitehouse 
2605ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2606d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
26071da177e4SLinus Torvalds 
260834954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2609d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
261034954ddcSFrancesco Fondelli 
261164053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
261264053beeSRobert Olsson 	 * fields.
261364053beeSRobert Olsson 	 */
2614fd2ea0a7SDavid S. Miller 	queue_map = pkt_dev->cur_queue_map;
261564053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
261664053beeSRobert Olsson 
26177ac5459eSDavid S. Miller 	datalen = (odev->hard_header_len + 16) & ~0xf;
2618e99b99b4SRobert Olsson 
2619e99b99b4SRobert Olsson 	if (pkt_dev->flags & F_NODE) {
2620e99b99b4SRobert Olsson 		int node;
2621e99b99b4SRobert Olsson 
2622e99b99b4SRobert Olsson 		if (pkt_dev->node >= 0)
2623e99b99b4SRobert Olsson 			node = pkt_dev->node;
2624e99b99b4SRobert Olsson 		else
2625e99b99b4SRobert Olsson 			node =  numa_node_id();
2626e99b99b4SRobert Olsson 
2627e99b99b4SRobert Olsson 		skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64
2628e99b99b4SRobert Olsson 				  + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node);
2629e99b99b4SRobert Olsson 		if (likely(skb)) {
2630e99b99b4SRobert Olsson 			skb_reserve(skb, NET_SKB_PAD);
2631e99b99b4SRobert Olsson 			skb->dev = odev;
2632e99b99b4SRobert Olsson 		}
2633e99b99b4SRobert Olsson 	}
2634e99b99b4SRobert Olsson 	else
2635e470757dSStephen Hemminger 	  skb = __netdev_alloc_skb(odev,
2636e470757dSStephen Hemminger 				   pkt_dev->cur_pkt_size + 64
2637e470757dSStephen Hemminger 				   + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
2638e99b99b4SRobert Olsson 
26391da177e4SLinus Torvalds 	if (!skb) {
26401da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
26411da177e4SLinus Torvalds 		return NULL;
26421da177e4SLinus Torvalds 	}
26431da177e4SLinus Torvalds 
26447ac5459eSDavid S. Miller 	skb_reserve(skb, datalen);
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
26471da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2648ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2649ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2650ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
265134954ddcSFrancesco Fondelli 
265234954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
265334954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
265434954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
26550f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
26560f37c605SAl Viro 					       pkt_dev->svlan_cfi,
26570f37c605SAl Viro 					       pkt_dev->svlan_p);
265834954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2659d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
266034954ddcSFrancesco Fondelli 		}
266134954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
26620f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
26630f37c605SAl Viro 				      pkt_dev->vlan_cfi,
26640f37c605SAl Viro 				      pkt_dev->vlan_p);
266534954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
2666d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IP);
266734954ddcSFrancesco Fondelli 	}
266834954ddcSFrancesco Fondelli 
266927a884dcSArnaldo Carvalho de Melo 	skb->network_header = skb->tail;
2670b0e380b1SArnaldo Carvalho de Melo 	skb->transport_header = skb->network_header + sizeof(struct iphdr);
2671ddc7b8e3SArnaldo Carvalho de Melo 	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
2672fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
2673ddc7b8e3SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
2674ddc7b8e3SArnaldo Carvalho de Melo 	udph = udp_hdr(skb);
26751da177e4SLinus Torvalds 
26761da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
2677252e3346SAl Viro 	*(__be16 *) & eth[12] = protocol;
26781da177e4SLinus Torvalds 
2679ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
2680ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
268116dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
26821da177e4SLinus Torvalds 	if (datalen < sizeof(struct pktgen_hdr))
26831da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
26841da177e4SLinus Torvalds 
26851da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
26861da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
26871da177e4SLinus Torvalds 	udph->len = htons(datalen + 8);	/* DATA + udphdr */
26881da177e4SLinus Torvalds 	udph->check = 0;	/* No checksum */
26891da177e4SLinus Torvalds 
26901da177e4SLinus Torvalds 	iph->ihl = 5;
26911da177e4SLinus Torvalds 	iph->version = 4;
26921da177e4SLinus Torvalds 	iph->ttl = 32;
26931ca7768cSFrancesco Fondelli 	iph->tos = pkt_dev->tos;
26941da177e4SLinus Torvalds 	iph->protocol = IPPROTO_UDP;	/* UDP */
26951da177e4SLinus Torvalds 	iph->saddr = pkt_dev->cur_saddr;
26961da177e4SLinus Torvalds 	iph->daddr = pkt_dev->cur_daddr;
269766ed1e5eSEric Dumazet 	iph->id = htons(pkt_dev->ip_id);
269866ed1e5eSEric Dumazet 	pkt_dev->ip_id++;
26991da177e4SLinus Torvalds 	iph->frag_off = 0;
27001da177e4SLinus Torvalds 	iplen = 20 + 8 + datalen;
27011da177e4SLinus Torvalds 	iph->tot_len = htons(iplen);
27021da177e4SLinus Torvalds 	iph->check = 0;
27031da177e4SLinus Torvalds 	iph->check = ip_fast_csum((void *)iph, iph->ihl);
2704ca6549afSSteven Whitehouse 	skb->protocol = protocol;
2705b0e380b1SArnaldo Carvalho de Melo 	skb->mac_header = (skb->network_header - ETH_HLEN -
270616dab72fSJamal Hadi Salim 			   pkt_dev->pkt_overhead);
27071da177e4SLinus Torvalds 	skb->dev = odev;
27081da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
27091da177e4SLinus Torvalds 
271066ed1e5eSEric Dumazet 	if (pkt_dev->nfrags <= 0) {
27111da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
271266ed1e5eSEric Dumazet 		memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr));
271366ed1e5eSEric Dumazet 	} else {
27141da177e4SLinus Torvalds 		int frags = pkt_dev->nfrags;
271566ed1e5eSEric Dumazet 		int i, len;
27161da177e4SLinus Torvalds 
27171da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
27181da177e4SLinus Torvalds 
27191da177e4SLinus Torvalds 		if (frags > MAX_SKB_FRAGS)
27201da177e4SLinus Torvalds 			frags = MAX_SKB_FRAGS;
27211da177e4SLinus Torvalds 		if (datalen > frags * PAGE_SIZE) {
272266ed1e5eSEric Dumazet 			len = datalen - frags * PAGE_SIZE;
272366ed1e5eSEric Dumazet 			memset(skb_put(skb, len), 0, len);
27241da177e4SLinus Torvalds 			datalen = frags * PAGE_SIZE;
27251da177e4SLinus Torvalds 		}
27261da177e4SLinus Torvalds 
27271da177e4SLinus Torvalds 		i = 0;
27281da177e4SLinus Torvalds 		while (datalen > 0) {
272966ed1e5eSEric Dumazet 			struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
27301da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page = page;
27311da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page_offset = 0;
27321da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size =
27331da177e4SLinus Torvalds 			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
27341da177e4SLinus Torvalds 			datalen -= skb_shinfo(skb)->frags[i].size;
27351da177e4SLinus Torvalds 			skb->len += skb_shinfo(skb)->frags[i].size;
27361da177e4SLinus Torvalds 			skb->data_len += skb_shinfo(skb)->frags[i].size;
27371da177e4SLinus Torvalds 			i++;
27381da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
27391da177e4SLinus Torvalds 		}
27401da177e4SLinus Torvalds 
27411da177e4SLinus Torvalds 		while (i < frags) {
27421da177e4SLinus Torvalds 			int rem;
27431da177e4SLinus Torvalds 
27441da177e4SLinus Torvalds 			if (i == 0)
27451da177e4SLinus Torvalds 				break;
27461da177e4SLinus Torvalds 
27471da177e4SLinus Torvalds 			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
27481da177e4SLinus Torvalds 			if (rem == 0)
27491da177e4SLinus Torvalds 				break;
27501da177e4SLinus Torvalds 
27511da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i - 1].size -= rem;
27521da177e4SLinus Torvalds 
2753222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i] =
2754222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1];
27551da177e4SLinus Torvalds 			get_page(skb_shinfo(skb)->frags[i].page);
2756222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page =
2757222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].page;
2758222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page_offset +=
2759222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].size;
27601da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size = rem;
27611da177e4SLinus Torvalds 			i++;
27621da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
27631da177e4SLinus Torvalds 		}
27641da177e4SLinus Torvalds 	}
27651da177e4SLinus Torvalds 
276663adc6fbSStephen Hemminger 	/* Stamp the time, and sequence number,
276763adc6fbSStephen Hemminger 	 * convert them to network byte order
276863adc6fbSStephen Hemminger 	 */
27691da177e4SLinus Torvalds 	if (pgh) {
27701da177e4SLinus Torvalds 		struct timeval timestamp;
27711da177e4SLinus Torvalds 
27721da177e4SLinus Torvalds 		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
27731da177e4SLinus Torvalds 		pgh->seq_num = htonl(pkt_dev->seq_num);
27741da177e4SLinus Torvalds 
27751da177e4SLinus Torvalds 		do_gettimeofday(&timestamp);
27761da177e4SLinus Torvalds 		pgh->tv_sec = htonl(timestamp.tv_sec);
27771da177e4SLinus Torvalds 		pgh->tv_usec = htonl(timestamp.tv_usec);
27781da177e4SLinus Torvalds 	}
27791da177e4SLinus Torvalds 
2780a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
2781a553e4a6SJamal Hadi Salim 	if (!process_ipsec(pkt_dev, skb, protocol))
2782a553e4a6SJamal Hadi Salim 		return NULL;
2783a553e4a6SJamal Hadi Salim #endif
2784a553e4a6SJamal Hadi Salim 
27851da177e4SLinus Torvalds 	return skb;
27861da177e4SLinus Torvalds }
27871da177e4SLinus Torvalds 
27881da177e4SLinus Torvalds /*
27891da177e4SLinus Torvalds  * scan_ip6, fmt_ip taken from dietlibc-0.21
27901da177e4SLinus Torvalds  * Author Felix von Leitner <felix-dietlibc@fefe.de>
27911da177e4SLinus Torvalds  *
27921da177e4SLinus Torvalds  * Slightly modified for kernel.
27931da177e4SLinus Torvalds  * Should be candidate for net/ipv4/utils.c
27941da177e4SLinus Torvalds  * --ro
27951da177e4SLinus Torvalds  */
27961da177e4SLinus Torvalds 
27971da177e4SLinus Torvalds static unsigned int scan_ip6(const char *s, char ip[16])
27981da177e4SLinus Torvalds {
27991da177e4SLinus Torvalds 	unsigned int i;
28001da177e4SLinus Torvalds 	unsigned int len = 0;
28011da177e4SLinus Torvalds 	unsigned long u;
28021da177e4SLinus Torvalds 	char suffix[16];
28031da177e4SLinus Torvalds 	unsigned int prefixlen = 0;
28041da177e4SLinus Torvalds 	unsigned int suffixlen = 0;
2805252e3346SAl Viro 	__be32 tmp;
2806cfcabdccSStephen Hemminger 	char *pos;
28071da177e4SLinus Torvalds 
2808222f1806SLuiz Capitulino 	for (i = 0; i < 16; i++)
2809222f1806SLuiz Capitulino 		ip[i] = 0;
28101da177e4SLinus Torvalds 
28111da177e4SLinus Torvalds 	for (;;) {
28121da177e4SLinus Torvalds 		if (*s == ':') {
28131da177e4SLinus Torvalds 			len++;
28141da177e4SLinus Torvalds 			if (s[1] == ':') {	/* Found "::", skip to part 2 */
28151da177e4SLinus Torvalds 				s += 2;
28161da177e4SLinus Torvalds 				len++;
28171da177e4SLinus Torvalds 				break;
28181da177e4SLinus Torvalds 			}
28191da177e4SLinus Torvalds 			s++;
28201da177e4SLinus Torvalds 		}
28211da177e4SLinus Torvalds 
2822cfcabdccSStephen Hemminger 		u = simple_strtoul(s, &pos, 16);
2823cfcabdccSStephen Hemminger 		i = pos - s;
2824222f1806SLuiz Capitulino 		if (!i)
2825222f1806SLuiz Capitulino 			return 0;
28261da177e4SLinus Torvalds 		if (prefixlen == 12 && s[i] == '.') {
28271da177e4SLinus Torvalds 
28281da177e4SLinus Torvalds 			/* the last 4 bytes may be written as IPv4 address */
28291da177e4SLinus Torvalds 
28301da177e4SLinus Torvalds 			tmp = in_aton(s);
28311da177e4SLinus Torvalds 			memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp));
28321da177e4SLinus Torvalds 			return i + len;
28331da177e4SLinus Torvalds 		}
28341da177e4SLinus Torvalds 		ip[prefixlen++] = (u >> 8);
28351da177e4SLinus Torvalds 		ip[prefixlen++] = (u & 255);
2836222f1806SLuiz Capitulino 		s += i;
2837222f1806SLuiz Capitulino 		len += i;
28381da177e4SLinus Torvalds 		if (prefixlen == 16)
28391da177e4SLinus Torvalds 			return len;
28401da177e4SLinus Torvalds 	}
28411da177e4SLinus Torvalds 
28421da177e4SLinus Torvalds /* part 2, after "::" */
28431da177e4SLinus Torvalds 	for (;;) {
28441da177e4SLinus Torvalds 		if (*s == ':') {
28451da177e4SLinus Torvalds 			if (suffixlen == 0)
28461da177e4SLinus Torvalds 				break;
28471da177e4SLinus Torvalds 			s++;
28481da177e4SLinus Torvalds 			len++;
28491da177e4SLinus Torvalds 		} else if (suffixlen != 0)
28501da177e4SLinus Torvalds 			break;
2851cfcabdccSStephen Hemminger 
2852cfcabdccSStephen Hemminger 		u = simple_strtol(s, &pos, 16);
2853cfcabdccSStephen Hemminger 		i = pos - s;
28541da177e4SLinus Torvalds 		if (!i) {
2855222f1806SLuiz Capitulino 			if (*s)
2856222f1806SLuiz Capitulino 				len--;
28571da177e4SLinus Torvalds 			break;
28581da177e4SLinus Torvalds 		}
28591da177e4SLinus Torvalds 		if (suffixlen + prefixlen <= 12 && s[i] == '.') {
28601da177e4SLinus Torvalds 			tmp = in_aton(s);
2861222f1806SLuiz Capitulino 			memcpy((struct in_addr *)(suffix + suffixlen), &tmp,
2862222f1806SLuiz Capitulino 			       sizeof(tmp));
28631da177e4SLinus Torvalds 			suffixlen += 4;
28641da177e4SLinus Torvalds 			len += strlen(s);
28651da177e4SLinus Torvalds 			break;
28661da177e4SLinus Torvalds 		}
28671da177e4SLinus Torvalds 		suffix[suffixlen++] = (u >> 8);
28681da177e4SLinus Torvalds 		suffix[suffixlen++] = (u & 255);
2869222f1806SLuiz Capitulino 		s += i;
2870222f1806SLuiz Capitulino 		len += i;
28711da177e4SLinus Torvalds 		if (prefixlen + suffixlen == 16)
28721da177e4SLinus Torvalds 			break;
28731da177e4SLinus Torvalds 	}
28741da177e4SLinus Torvalds 	for (i = 0; i < suffixlen; i++)
28751da177e4SLinus Torvalds 		ip[16 - suffixlen + i] = suffix[i];
28761da177e4SLinus Torvalds 	return len;
28771da177e4SLinus Torvalds }
28781da177e4SLinus Torvalds 
2879222f1806SLuiz Capitulino static char tohex(char hexdigit)
2880222f1806SLuiz Capitulino {
28811da177e4SLinus Torvalds 	return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
28821da177e4SLinus Torvalds }
28831da177e4SLinus Torvalds 
2884222f1806SLuiz Capitulino static int fmt_xlong(char *s, unsigned int i)
2885222f1806SLuiz Capitulino {
28861da177e4SLinus Torvalds 	char *bak = s;
2887222f1806SLuiz Capitulino 	*s = tohex((i >> 12) & 0xf);
2888222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2889222f1806SLuiz Capitulino 		++s;
2890222f1806SLuiz Capitulino 	*s = tohex((i >> 8) & 0xf);
2891222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2892222f1806SLuiz Capitulino 		++s;
2893222f1806SLuiz Capitulino 	*s = tohex((i >> 4) & 0xf);
2894222f1806SLuiz Capitulino 	if (s != bak || *s != '0')
2895222f1806SLuiz Capitulino 		++s;
28961da177e4SLinus Torvalds 	*s = tohex(i & 0xf);
28971da177e4SLinus Torvalds 	return s - bak + 1;
28981da177e4SLinus Torvalds }
28991da177e4SLinus Torvalds 
2900222f1806SLuiz Capitulino static unsigned int fmt_ip6(char *s, const char ip[16])
2901222f1806SLuiz Capitulino {
29021da177e4SLinus Torvalds 	unsigned int len;
29031da177e4SLinus Torvalds 	unsigned int i;
29041da177e4SLinus Torvalds 	unsigned int temp;
29051da177e4SLinus Torvalds 	unsigned int compressing;
29061da177e4SLinus Torvalds 	int j;
29071da177e4SLinus Torvalds 
2908222f1806SLuiz Capitulino 	len = 0;
2909222f1806SLuiz Capitulino 	compressing = 0;
29101da177e4SLinus Torvalds 	for (j = 0; j < 16; j += 2) {
29111da177e4SLinus Torvalds 
29121da177e4SLinus Torvalds #ifdef V4MAPPEDPREFIX
29131da177e4SLinus Torvalds 		if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) {
29141da177e4SLinus Torvalds 			inet_ntoa_r(*(struct in_addr *)(ip + 12), s);
29151da177e4SLinus Torvalds 			temp = strlen(s);
29161da177e4SLinus Torvalds 			return len + temp;
29171da177e4SLinus Torvalds 		}
29181da177e4SLinus Torvalds #endif
29191da177e4SLinus Torvalds 		temp = ((unsigned long)(unsigned char)ip[j] << 8) +
29201da177e4SLinus Torvalds 		    (unsigned long)(unsigned char)ip[j + 1];
29211da177e4SLinus Torvalds 		if (temp == 0) {
29221da177e4SLinus Torvalds 			if (!compressing) {
29231da177e4SLinus Torvalds 				compressing = 1;
29241da177e4SLinus Torvalds 				if (j == 0) {
2925222f1806SLuiz Capitulino 					*s++ = ':';
2926222f1806SLuiz Capitulino 					++len;
29271da177e4SLinus Torvalds 				}
29281da177e4SLinus Torvalds 			}
29291da177e4SLinus Torvalds 		} else {
29301da177e4SLinus Torvalds 			if (compressing) {
29311da177e4SLinus Torvalds 				compressing = 0;
2932222f1806SLuiz Capitulino 				*s++ = ':';
2933222f1806SLuiz Capitulino 				++len;
29341da177e4SLinus Torvalds 			}
2935222f1806SLuiz Capitulino 			i = fmt_xlong(s, temp);
2936222f1806SLuiz Capitulino 			len += i;
2937222f1806SLuiz Capitulino 			s += i;
29381da177e4SLinus Torvalds 			if (j < 14) {
29391da177e4SLinus Torvalds 				*s++ = ':';
29401da177e4SLinus Torvalds 				++len;
29411da177e4SLinus Torvalds 			}
29421da177e4SLinus Torvalds 		}
29431da177e4SLinus Torvalds 	}
29441da177e4SLinus Torvalds 	if (compressing) {
2945222f1806SLuiz Capitulino 		*s++ = ':';
2946222f1806SLuiz Capitulino 		++len;
29471da177e4SLinus Torvalds 	}
29481da177e4SLinus Torvalds 	*s = 0;
29491da177e4SLinus Torvalds 	return len;
29501da177e4SLinus Torvalds }
29511da177e4SLinus Torvalds 
29521da177e4SLinus Torvalds static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
29531da177e4SLinus Torvalds 					struct pktgen_dev *pkt_dev)
29541da177e4SLinus Torvalds {
29551da177e4SLinus Torvalds 	struct sk_buff *skb = NULL;
29561da177e4SLinus Torvalds 	__u8 *eth;
29571da177e4SLinus Torvalds 	struct udphdr *udph;
29581da177e4SLinus Torvalds 	int datalen;
29591da177e4SLinus Torvalds 	struct ipv6hdr *iph;
29601da177e4SLinus Torvalds 	struct pktgen_hdr *pgh = NULL;
2961d5f1ce9aSStephen Hemminger 	__be16 protocol = htons(ETH_P_IPV6);
2962ca6549afSSteven Whitehouse 	__be32 *mpls;
296334954ddcSFrancesco Fondelli 	__be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
296434954ddcSFrancesco Fondelli 	__be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
296534954ddcSFrancesco Fondelli 	__be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
296634954ddcSFrancesco Fondelli 	__be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2967fd2ea0a7SDavid S. Miller 	u16 queue_map;
2968ca6549afSSteven Whitehouse 
2969ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2970d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_MPLS_UC);
29711da177e4SLinus Torvalds 
297234954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff)
2973d5f1ce9aSStephen Hemminger 		protocol = htons(ETH_P_8021Q);
297434954ddcSFrancesco Fondelli 
297564053beeSRobert Olsson 	/* Update any of the values, used when we're incrementing various
297664053beeSRobert Olsson 	 * fields.
297764053beeSRobert Olsson 	 */
2978fd2ea0a7SDavid S. Miller 	queue_map = pkt_dev->cur_queue_map;
297964053beeSRobert Olsson 	mod_cur_headers(pkt_dev);
298064053beeSRobert Olsson 
2981e470757dSStephen Hemminger 	skb = __netdev_alloc_skb(odev,
2982e470757dSStephen Hemminger 				 pkt_dev->cur_pkt_size + 64
2983e470757dSStephen Hemminger 				 + 16 + pkt_dev->pkt_overhead, GFP_NOWAIT);
29841da177e4SLinus Torvalds 	if (!skb) {
29851da177e4SLinus Torvalds 		sprintf(pkt_dev->result, "No memory");
29861da177e4SLinus Torvalds 		return NULL;
29871da177e4SLinus Torvalds 	}
29881da177e4SLinus Torvalds 
29891da177e4SLinus Torvalds 	skb_reserve(skb, 16);
29901da177e4SLinus Torvalds 
29911da177e4SLinus Torvalds 	/*  Reserve for ethernet and IP header  */
29921da177e4SLinus Torvalds 	eth = (__u8 *) skb_push(skb, 14);
2993ca6549afSSteven Whitehouse 	mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
2994ca6549afSSteven Whitehouse 	if (pkt_dev->nr_labels)
2995ca6549afSSteven Whitehouse 		mpls_push(mpls, pkt_dev);
299634954ddcSFrancesco Fondelli 
299734954ddcSFrancesco Fondelli 	if (pkt_dev->vlan_id != 0xffff) {
299834954ddcSFrancesco Fondelli 		if (pkt_dev->svlan_id != 0xffff) {
299934954ddcSFrancesco Fondelli 			svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
30000f37c605SAl Viro 			*svlan_tci = build_tci(pkt_dev->svlan_id,
30010f37c605SAl Viro 					       pkt_dev->svlan_cfi,
30020f37c605SAl Viro 					       pkt_dev->svlan_p);
300334954ddcSFrancesco Fondelli 			svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
3004d5f1ce9aSStephen Hemminger 			*svlan_encapsulated_proto = htons(ETH_P_8021Q);
300534954ddcSFrancesco Fondelli 		}
300634954ddcSFrancesco Fondelli 		vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
30070f37c605SAl Viro 		*vlan_tci = build_tci(pkt_dev->vlan_id,
30080f37c605SAl Viro 				      pkt_dev->vlan_cfi,
30090f37c605SAl Viro 				      pkt_dev->vlan_p);
301034954ddcSFrancesco Fondelli 		vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
3011d5f1ce9aSStephen Hemminger 		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
301234954ddcSFrancesco Fondelli 	}
301334954ddcSFrancesco Fondelli 
301427a884dcSArnaldo Carvalho de Melo 	skb->network_header = skb->tail;
3015b0e380b1SArnaldo Carvalho de Melo 	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
3016ddc7b8e3SArnaldo Carvalho de Melo 	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
3017fd2ea0a7SDavid S. Miller 	skb_set_queue_mapping(skb, queue_map);
3018ddc7b8e3SArnaldo Carvalho de Melo 	iph = ipv6_hdr(skb);
3019ddc7b8e3SArnaldo Carvalho de Melo 	udph = udp_hdr(skb);
30201da177e4SLinus Torvalds 
30211da177e4SLinus Torvalds 	memcpy(eth, pkt_dev->hh, 12);
3022252e3346SAl Viro 	*(__be16 *) &eth[12] = protocol;
30231da177e4SLinus Torvalds 
3024ca6549afSSteven Whitehouse 	/* Eth + IPh + UDPh + mpls */
3025ca6549afSSteven Whitehouse 	datalen = pkt_dev->cur_pkt_size - 14 -
3026ca6549afSSteven Whitehouse 		  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
302716dab72fSJamal Hadi Salim 		  pkt_dev->pkt_overhead;
30281da177e4SLinus Torvalds 
30291da177e4SLinus Torvalds 	if (datalen < sizeof(struct pktgen_hdr)) {
30301da177e4SLinus Torvalds 		datalen = sizeof(struct pktgen_hdr);
30311da177e4SLinus Torvalds 		if (net_ratelimit())
3032f9467eaeSJoe Perches 			pr_info("increased datalen to %d\n", datalen);
30331da177e4SLinus Torvalds 	}
30341da177e4SLinus Torvalds 
30351da177e4SLinus Torvalds 	udph->source = htons(pkt_dev->cur_udp_src);
30361da177e4SLinus Torvalds 	udph->dest = htons(pkt_dev->cur_udp_dst);
30371da177e4SLinus Torvalds 	udph->len = htons(datalen + sizeof(struct udphdr));
30381da177e4SLinus Torvalds 	udph->check = 0;	/* No checksum */
30391da177e4SLinus Torvalds 
3040d5f1ce9aSStephen Hemminger 	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
30411da177e4SLinus Torvalds 
30421ca7768cSFrancesco Fondelli 	if (pkt_dev->traffic_class) {
30431ca7768cSFrancesco Fondelli 		/* Version + traffic class + flow (0) */
3044252e3346SAl Viro 		*(__be32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
30451ca7768cSFrancesco Fondelli 	}
30461ca7768cSFrancesco Fondelli 
30471da177e4SLinus Torvalds 	iph->hop_limit = 32;
30481da177e4SLinus Torvalds 
30491da177e4SLinus Torvalds 	iph->payload_len = htons(sizeof(struct udphdr) + datalen);
30501da177e4SLinus Torvalds 	iph->nexthdr = IPPROTO_UDP;
30511da177e4SLinus Torvalds 
30521da177e4SLinus Torvalds 	ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
30531da177e4SLinus Torvalds 	ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
30541da177e4SLinus Torvalds 
3055b0e380b1SArnaldo Carvalho de Melo 	skb->mac_header = (skb->network_header - ETH_HLEN -
305616dab72fSJamal Hadi Salim 			   pkt_dev->pkt_overhead);
3057ca6549afSSteven Whitehouse 	skb->protocol = protocol;
30581da177e4SLinus Torvalds 	skb->dev = odev;
30591da177e4SLinus Torvalds 	skb->pkt_type = PACKET_HOST;
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 	if (pkt_dev->nfrags <= 0)
30621da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
30631da177e4SLinus Torvalds 	else {
30641da177e4SLinus Torvalds 		int frags = pkt_dev->nfrags;
30651da177e4SLinus Torvalds 		int i;
30661da177e4SLinus Torvalds 
30671da177e4SLinus Torvalds 		pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8);
30681da177e4SLinus Torvalds 
30691da177e4SLinus Torvalds 		if (frags > MAX_SKB_FRAGS)
30701da177e4SLinus Torvalds 			frags = MAX_SKB_FRAGS;
30711da177e4SLinus Torvalds 		if (datalen > frags * PAGE_SIZE) {
30721da177e4SLinus Torvalds 			skb_put(skb, datalen - frags * PAGE_SIZE);
30731da177e4SLinus Torvalds 			datalen = frags * PAGE_SIZE;
30741da177e4SLinus Torvalds 		}
30751da177e4SLinus Torvalds 
30761da177e4SLinus Torvalds 		i = 0;
30771da177e4SLinus Torvalds 		while (datalen > 0) {
30781da177e4SLinus Torvalds 			struct page *page = alloc_pages(GFP_KERNEL, 0);
30791da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page = page;
30801da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].page_offset = 0;
30811da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size =
30821da177e4SLinus Torvalds 			    (datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
30831da177e4SLinus Torvalds 			datalen -= skb_shinfo(skb)->frags[i].size;
30841da177e4SLinus Torvalds 			skb->len += skb_shinfo(skb)->frags[i].size;
30851da177e4SLinus Torvalds 			skb->data_len += skb_shinfo(skb)->frags[i].size;
30861da177e4SLinus Torvalds 			i++;
30871da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
30881da177e4SLinus Torvalds 		}
30891da177e4SLinus Torvalds 
30901da177e4SLinus Torvalds 		while (i < frags) {
30911da177e4SLinus Torvalds 			int rem;
30921da177e4SLinus Torvalds 
30931da177e4SLinus Torvalds 			if (i == 0)
30941da177e4SLinus Torvalds 				break;
30951da177e4SLinus Torvalds 
30961da177e4SLinus Torvalds 			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
30971da177e4SLinus Torvalds 			if (rem == 0)
30981da177e4SLinus Torvalds 				break;
30991da177e4SLinus Torvalds 
31001da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i - 1].size -= rem;
31011da177e4SLinus Torvalds 
3102222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i] =
3103222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1];
31041da177e4SLinus Torvalds 			get_page(skb_shinfo(skb)->frags[i].page);
3105222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page =
3106222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].page;
3107222f1806SLuiz Capitulino 			skb_shinfo(skb)->frags[i].page_offset +=
3108222f1806SLuiz Capitulino 			    skb_shinfo(skb)->frags[i - 1].size;
31091da177e4SLinus Torvalds 			skb_shinfo(skb)->frags[i].size = rem;
31101da177e4SLinus Torvalds 			i++;
31111da177e4SLinus Torvalds 			skb_shinfo(skb)->nr_frags = i;
31121da177e4SLinus Torvalds 		}
31131da177e4SLinus Torvalds 	}
31141da177e4SLinus Torvalds 
311563adc6fbSStephen Hemminger 	/* Stamp the time, and sequence number,
311663adc6fbSStephen Hemminger 	 * convert them to network byte order
311763adc6fbSStephen Hemminger 	 * should we update cloned packets too ?
311863adc6fbSStephen Hemminger 	 */
31191da177e4SLinus Torvalds 	if (pgh) {
31201da177e4SLinus Torvalds 		struct timeval timestamp;
31211da177e4SLinus Torvalds 
31221da177e4SLinus Torvalds 		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
31231da177e4SLinus Torvalds 		pgh->seq_num = htonl(pkt_dev->seq_num);
31241da177e4SLinus Torvalds 
31251da177e4SLinus Torvalds 		do_gettimeofday(&timestamp);
31261da177e4SLinus Torvalds 		pgh->tv_sec = htonl(timestamp.tv_sec);
31271da177e4SLinus Torvalds 		pgh->tv_usec = htonl(timestamp.tv_usec);
31281da177e4SLinus Torvalds 	}
312934954ddcSFrancesco Fondelli 	/* pkt_dev->seq_num++; FF: you really mean this? */
31301da177e4SLinus Torvalds 
31311da177e4SLinus Torvalds 	return skb;
31321da177e4SLinus Torvalds }
31331da177e4SLinus Torvalds 
3134475ac1e4SStephen Hemminger static struct sk_buff *fill_packet(struct net_device *odev,
31351da177e4SLinus Torvalds 				   struct pktgen_dev *pkt_dev)
31361da177e4SLinus Torvalds {
31371da177e4SLinus Torvalds 	if (pkt_dev->flags & F_IPV6)
31381da177e4SLinus Torvalds 		return fill_packet_ipv6(odev, pkt_dev);
31391da177e4SLinus Torvalds 	else
31401da177e4SLinus Torvalds 		return fill_packet_ipv4(odev, pkt_dev);
31411da177e4SLinus Torvalds }
31421da177e4SLinus Torvalds 
31431da177e4SLinus Torvalds static void pktgen_clear_counters(struct pktgen_dev *pkt_dev)
31441da177e4SLinus Torvalds {
31451da177e4SLinus Torvalds 	pkt_dev->seq_num = 1;
31461da177e4SLinus Torvalds 	pkt_dev->idle_acc = 0;
31471da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
31481da177e4SLinus Torvalds 	pkt_dev->tx_bytes = 0;
31491da177e4SLinus Torvalds 	pkt_dev->errors = 0;
31501da177e4SLinus Torvalds }
31511da177e4SLinus Torvalds 
31521da177e4SLinus Torvalds /* Set up structure for sending pkts, clear counters */
31531da177e4SLinus Torvalds 
31541da177e4SLinus Torvalds static void pktgen_run(struct pktgen_thread *t)
31551da177e4SLinus Torvalds {
3156c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
31571da177e4SLinus Torvalds 	int started = 0;
31581da177e4SLinus Torvalds 
3159f9467eaeSJoe Perches 	func_enter();
31601da177e4SLinus Torvalds 
31611da177e4SLinus Torvalds 	if_lock(t);
3162c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 		/*
31651da177e4SLinus Torvalds 		 * setup odev and create initial packet.
31661da177e4SLinus Torvalds 		 */
31671da177e4SLinus Torvalds 		pktgen_setup_inject(pkt_dev);
31681da177e4SLinus Torvalds 
31691da177e4SLinus Torvalds 		if (pkt_dev->odev) {
31701da177e4SLinus Torvalds 			pktgen_clear_counters(pkt_dev);
31711da177e4SLinus Torvalds 			pkt_dev->running = 1;	/* Cranke yeself! */
31721da177e4SLinus Torvalds 			pkt_dev->skb = NULL;
3173fd29cf72SStephen Hemminger 			pkt_dev->started_at =
3174fd29cf72SStephen Hemminger 				pkt_dev->next_tx = ktime_now();
3175fd29cf72SStephen Hemminger 
317616dab72fSJamal Hadi Salim 			set_pkt_overhead(pkt_dev);
31771da177e4SLinus Torvalds 
31781da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Starting");
31791da177e4SLinus Torvalds 			started++;
3180222f1806SLuiz Capitulino 		} else
31811da177e4SLinus Torvalds 			strcpy(pkt_dev->result, "Error starting");
31821da177e4SLinus Torvalds 	}
31831da177e4SLinus Torvalds 	if_unlock(t);
3184222f1806SLuiz Capitulino 	if (started)
3185222f1806SLuiz Capitulino 		t->control &= ~(T_STOP);
31861da177e4SLinus Torvalds }
31871da177e4SLinus Torvalds 
31881da177e4SLinus Torvalds static void pktgen_stop_all_threads_ifs(void)
31891da177e4SLinus Torvalds {
3190cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
31911da177e4SLinus Torvalds 
3192f9467eaeSJoe Perches 	func_enter();
31931da177e4SLinus Torvalds 
31946146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3195cdcdbe0bSLuiz Capitulino 
3196cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list)
319795ed63f7SArthur Kepner 		t->control |= T_STOP;
3198cdcdbe0bSLuiz Capitulino 
31996146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32001da177e4SLinus Torvalds }
32011da177e4SLinus Torvalds 
3202648fda74SStephen Hemminger static int thread_is_running(const struct pktgen_thread *t)
32031da177e4SLinus Torvalds {
3204648fda74SStephen Hemminger 	const struct pktgen_dev *pkt_dev;
32051da177e4SLinus Torvalds 
3206c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list)
3207648fda74SStephen Hemminger 		if (pkt_dev->running)
3208648fda74SStephen Hemminger 			return 1;
3209648fda74SStephen Hemminger 	return 0;
32101da177e4SLinus Torvalds }
32111da177e4SLinus Torvalds 
32121da177e4SLinus Torvalds static int pktgen_wait_thread_run(struct pktgen_thread *t)
32131da177e4SLinus Torvalds {
32141da177e4SLinus Torvalds 	if_lock(t);
32151da177e4SLinus Torvalds 
32161da177e4SLinus Torvalds 	while (thread_is_running(t)) {
32171da177e4SLinus Torvalds 
32181da177e4SLinus Torvalds 		if_unlock(t);
32191da177e4SLinus Torvalds 
32201da177e4SLinus Torvalds 		msleep_interruptible(100);
32211da177e4SLinus Torvalds 
32221da177e4SLinus Torvalds 		if (signal_pending(current))
32231da177e4SLinus Torvalds 			goto signal;
32241da177e4SLinus Torvalds 		if_lock(t);
32251da177e4SLinus Torvalds 	}
32261da177e4SLinus Torvalds 	if_unlock(t);
32271da177e4SLinus Torvalds 	return 1;
32281da177e4SLinus Torvalds signal:
32291da177e4SLinus Torvalds 	return 0;
32301da177e4SLinus Torvalds }
32311da177e4SLinus Torvalds 
32321da177e4SLinus Torvalds static int pktgen_wait_all_threads_run(void)
32331da177e4SLinus Torvalds {
3234cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
32351da177e4SLinus Torvalds 	int sig = 1;
32361da177e4SLinus Torvalds 
32376146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
3238cdcdbe0bSLuiz Capitulino 
3239cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list) {
32401da177e4SLinus Torvalds 		sig = pktgen_wait_thread_run(t);
3241222f1806SLuiz Capitulino 		if (sig == 0)
3242222f1806SLuiz Capitulino 			break;
32431da177e4SLinus Torvalds 	}
3244cdcdbe0bSLuiz Capitulino 
3245cdcdbe0bSLuiz Capitulino 	if (sig == 0)
3246cdcdbe0bSLuiz Capitulino 		list_for_each_entry(t, &pktgen_threads, th_list)
32471da177e4SLinus Torvalds 			t->control |= (T_STOP);
3248cdcdbe0bSLuiz Capitulino 
32496146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32501da177e4SLinus Torvalds 	return sig;
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds 
32531da177e4SLinus Torvalds static void pktgen_run_all_threads(void)
32541da177e4SLinus Torvalds {
3255cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
32561da177e4SLinus Torvalds 
3257f9467eaeSJoe Perches 	func_enter();
32581da177e4SLinus Torvalds 
32596146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
32601da177e4SLinus Torvalds 
3261cdcdbe0bSLuiz Capitulino 	list_for_each_entry(t, &pktgen_threads, th_list)
32621da177e4SLinus Torvalds 		t->control |= (T_RUN);
3263cdcdbe0bSLuiz Capitulino 
32646146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
32651da177e4SLinus Torvalds 
326663adc6fbSStephen Hemminger 	/* Propagate thread->control  */
326763adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
32681da177e4SLinus Torvalds 
32691da177e4SLinus Torvalds 	pktgen_wait_all_threads_run();
32701da177e4SLinus Torvalds }
32711da177e4SLinus Torvalds 
3272eb37b41cSJesse Brandeburg static void pktgen_reset_all_threads(void)
3273eb37b41cSJesse Brandeburg {
3274eb37b41cSJesse Brandeburg 	struct pktgen_thread *t;
3275eb37b41cSJesse Brandeburg 
3276f9467eaeSJoe Perches 	func_enter();
3277eb37b41cSJesse Brandeburg 
3278eb37b41cSJesse Brandeburg 	mutex_lock(&pktgen_thread_lock);
3279eb37b41cSJesse Brandeburg 
3280eb37b41cSJesse Brandeburg 	list_for_each_entry(t, &pktgen_threads, th_list)
3281eb37b41cSJesse Brandeburg 		t->control |= (T_REMDEVALL);
3282eb37b41cSJesse Brandeburg 
3283eb37b41cSJesse Brandeburg 	mutex_unlock(&pktgen_thread_lock);
3284eb37b41cSJesse Brandeburg 
328563adc6fbSStephen Hemminger 	/* Propagate thread->control  */
328663adc6fbSStephen Hemminger 	schedule_timeout_interruptible(msecs_to_jiffies(125));
3287eb37b41cSJesse Brandeburg 
3288eb37b41cSJesse Brandeburg 	pktgen_wait_all_threads_run();
3289eb37b41cSJesse Brandeburg }
3290eb37b41cSJesse Brandeburg 
32911da177e4SLinus Torvalds static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
32921da177e4SLinus Torvalds {
3293fd29cf72SStephen Hemminger 	__u64 bps, mbps, pps;
32941da177e4SLinus Torvalds 	char *p = pkt_dev->result;
3295fd29cf72SStephen Hemminger 	ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
3296fd29cf72SStephen Hemminger 				    pkt_dev->started_at);
3297fd29cf72SStephen Hemminger 	ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
32981da177e4SLinus Torvalds 
3299fd29cf72SStephen Hemminger 	p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
3300fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(elapsed),
3301fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
3302fd29cf72SStephen Hemminger 		     (unsigned long long)ktime_to_us(idle),
33031da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->sofar,
33041da177e4SLinus Torvalds 		     pkt_dev->cur_pkt_size, nr_frags);
33051da177e4SLinus Torvalds 
3306fd29cf72SStephen Hemminger 	pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
3307fd29cf72SStephen Hemminger 			ktime_to_ns(elapsed));
33081da177e4SLinus Torvalds 
33091da177e4SLinus Torvalds 	bps = pps * 8 * pkt_dev->cur_pkt_size;
33101da177e4SLinus Torvalds 
33111da177e4SLinus Torvalds 	mbps = bps;
33121da177e4SLinus Torvalds 	do_div(mbps, 1000000);
33131da177e4SLinus Torvalds 	p += sprintf(p, "  %llupps %lluMb/sec (%llubps) errors: %llu",
33141da177e4SLinus Torvalds 		     (unsigned long long)pps,
33151da177e4SLinus Torvalds 		     (unsigned long long)mbps,
33161da177e4SLinus Torvalds 		     (unsigned long long)bps,
33171da177e4SLinus Torvalds 		     (unsigned long long)pkt_dev->errors);
33181da177e4SLinus Torvalds }
33191da177e4SLinus Torvalds 
33201da177e4SLinus Torvalds /* Set stopped-at timer, remove from running list, do counters & statistics */
33211da177e4SLinus Torvalds static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
33221da177e4SLinus Torvalds {
3323222f1806SLuiz Capitulino 	int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
33241da177e4SLinus Torvalds 
33251da177e4SLinus Torvalds 	if (!pkt_dev->running) {
3326f9467eaeSJoe Perches 		pr_warning("interface: %s is already stopped\n",
3327f9467eaeSJoe Perches 			   pkt_dev->odevname);
33281da177e4SLinus Torvalds 		return -EINVAL;
33291da177e4SLinus Torvalds 	}
33301da177e4SLinus Torvalds 
33313bda06a3SStephen Hemminger 	kfree_skb(pkt_dev->skb);
33323bda06a3SStephen Hemminger 	pkt_dev->skb = NULL;
3333fd29cf72SStephen Hemminger 	pkt_dev->stopped_at = ktime_now();
33341da177e4SLinus Torvalds 	pkt_dev->running = 0;
33351da177e4SLinus Torvalds 
333695ed63f7SArthur Kepner 	show_results(pkt_dev, nr_frags);
33371da177e4SLinus Torvalds 
33381da177e4SLinus Torvalds 	return 0;
33391da177e4SLinus Torvalds }
33401da177e4SLinus Torvalds 
33411da177e4SLinus Torvalds static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
33421da177e4SLinus Torvalds {
3343c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev, *best = NULL;
33441da177e4SLinus Torvalds 
33451da177e4SLinus Torvalds 	if_lock(t);
33461da177e4SLinus Torvalds 
3347c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
3348c26a8016SLuiz Capitulino 		if (!pkt_dev->running)
3349222f1806SLuiz Capitulino 			continue;
3350222f1806SLuiz Capitulino 		if (best == NULL)
3351c26a8016SLuiz Capitulino 			best = pkt_dev;
3352fd29cf72SStephen Hemminger 		else if (ktime_lt(pkt_dev->next_tx, best->next_tx))
3353c26a8016SLuiz Capitulino 			best = pkt_dev;
33541da177e4SLinus Torvalds 	}
33551da177e4SLinus Torvalds 	if_unlock(t);
33561da177e4SLinus Torvalds 	return best;
33571da177e4SLinus Torvalds }
33581da177e4SLinus Torvalds 
3359222f1806SLuiz Capitulino static void pktgen_stop(struct pktgen_thread *t)
3360222f1806SLuiz Capitulino {
3361c26a8016SLuiz Capitulino 	struct pktgen_dev *pkt_dev;
33621da177e4SLinus Torvalds 
3363f9467eaeSJoe Perches 	func_enter();
33641da177e4SLinus Torvalds 
33651da177e4SLinus Torvalds 	if_lock(t);
33661da177e4SLinus Torvalds 
3367c26a8016SLuiz Capitulino 	list_for_each_entry(pkt_dev, &t->if_list, list) {
3368c26a8016SLuiz Capitulino 		pktgen_stop_device(pkt_dev);
336995ed63f7SArthur Kepner 	}
337095ed63f7SArthur Kepner 
337195ed63f7SArthur Kepner 	if_unlock(t);
337295ed63f7SArthur Kepner }
337395ed63f7SArthur Kepner 
337495ed63f7SArthur Kepner /*
337595ed63f7SArthur Kepner  * one of our devices needs to be removed - find it
337695ed63f7SArthur Kepner  * and remove it
337795ed63f7SArthur Kepner  */
337895ed63f7SArthur Kepner static void pktgen_rem_one_if(struct pktgen_thread *t)
337995ed63f7SArthur Kepner {
3380c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3381c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
338295ed63f7SArthur Kepner 
3383f9467eaeSJoe Perches 	func_enter();
338495ed63f7SArthur Kepner 
338595ed63f7SArthur Kepner 	if_lock(t);
338695ed63f7SArthur Kepner 
3387c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3388c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
338995ed63f7SArthur Kepner 
3390222f1806SLuiz Capitulino 		if (!cur->removal_mark)
3391222f1806SLuiz Capitulino 			continue;
339295ed63f7SArthur Kepner 
339395ed63f7SArthur Kepner 		kfree_skb(cur->skb);
339495ed63f7SArthur Kepner 		cur->skb = NULL;
339595ed63f7SArthur Kepner 
339695ed63f7SArthur Kepner 		pktgen_remove_device(t, cur);
339795ed63f7SArthur Kepner 
339895ed63f7SArthur Kepner 		break;
339995ed63f7SArthur Kepner 	}
34001da177e4SLinus Torvalds 
34011da177e4SLinus Torvalds 	if_unlock(t);
34021da177e4SLinus Torvalds }
34031da177e4SLinus Torvalds 
34041da177e4SLinus Torvalds static void pktgen_rem_all_ifs(struct pktgen_thread *t)
34051da177e4SLinus Torvalds {
3406c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3407c26a8016SLuiz Capitulino 	struct pktgen_dev *cur;
34081da177e4SLinus Torvalds 
3409f9467eaeSJoe Perches 	func_enter();
3410f9467eaeSJoe Perches 
34111da177e4SLinus Torvalds 	/* Remove all devices, free mem */
34121da177e4SLinus Torvalds 
34131da177e4SLinus Torvalds 	if_lock(t);
34141da177e4SLinus Torvalds 
3415c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3416c26a8016SLuiz Capitulino 		cur = list_entry(q, struct pktgen_dev, list);
341795ed63f7SArthur Kepner 
341895ed63f7SArthur Kepner 		kfree_skb(cur->skb);
341995ed63f7SArthur Kepner 		cur->skb = NULL;
342095ed63f7SArthur Kepner 
34211da177e4SLinus Torvalds 		pktgen_remove_device(t, cur);
34221da177e4SLinus Torvalds 	}
34231da177e4SLinus Torvalds 
34241da177e4SLinus Torvalds 	if_unlock(t);
34251da177e4SLinus Torvalds }
34261da177e4SLinus Torvalds 
34271da177e4SLinus Torvalds static void pktgen_rem_thread(struct pktgen_thread *t)
34281da177e4SLinus Torvalds {
34291da177e4SLinus Torvalds 	/* Remove from the thread list */
34301da177e4SLinus Torvalds 
3431ee74baa7SDavid S. Miller 	remove_proc_entry(t->tsk->comm, pg_proc_dir);
34321da177e4SLinus Torvalds 
34336146e6a4SLuiz Capitulino 	mutex_lock(&pktgen_thread_lock);
34341da177e4SLinus Torvalds 
3435cdcdbe0bSLuiz Capitulino 	list_del(&t->th_list);
3436cdcdbe0bSLuiz Capitulino 
34376146e6a4SLuiz Capitulino 	mutex_unlock(&pktgen_thread_lock);
34381da177e4SLinus Torvalds }
34391da177e4SLinus Torvalds 
3440ef87979cSStephen Hemminger static void pktgen_resched(struct pktgen_dev *pkt_dev)
34413791decbSStephen Hemminger {
3442fd29cf72SStephen Hemminger 	ktime_t idle_start = ktime_now();
34433791decbSStephen Hemminger 	schedule();
3444fd29cf72SStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
34453791decbSStephen Hemminger }
34463791decbSStephen Hemminger 
3447ef87979cSStephen Hemminger static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
3448ef87979cSStephen Hemminger {
3449ef87979cSStephen Hemminger 	ktime_t idle_start = ktime_now();
3450ef87979cSStephen Hemminger 
3451ef87979cSStephen Hemminger 	while (atomic_read(&(pkt_dev->skb->users)) != 1) {
3452ef87979cSStephen Hemminger 		if (signal_pending(current))
3453ef87979cSStephen Hemminger 			break;
3454ef87979cSStephen Hemminger 
3455ef87979cSStephen Hemminger 		if (need_resched())
3456ef87979cSStephen Hemminger 			pktgen_resched(pkt_dev);
3457ef87979cSStephen Hemminger 		else
3458ef87979cSStephen Hemminger 			cpu_relax();
3459ef87979cSStephen Hemminger 	}
3460ef87979cSStephen Hemminger 	pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
3461ef87979cSStephen Hemminger }
3462fd29cf72SStephen Hemminger 
3463475ac1e4SStephen Hemminger static void pktgen_xmit(struct pktgen_dev *pkt_dev)
34641da177e4SLinus Torvalds {
346500829823SStephen Hemminger 	struct net_device *odev = pkt_dev->odev;
34666fef4c0cSStephen Hemminger 	netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *)
346700829823SStephen Hemminger 		= odev->netdev_ops->ndo_start_xmit;
3468fd2ea0a7SDavid S. Miller 	struct netdev_queue *txq;
3469fd2ea0a7SDavid S. Miller 	u16 queue_map;
34701da177e4SLinus Torvalds 	int ret;
34711da177e4SLinus Torvalds 
3472ef87979cSStephen Hemminger 	/* If device is offline, then don't send */
3473ef87979cSStephen Hemminger 	if (unlikely(!netif_running(odev) || !netif_carrier_ok(odev))) {
34741da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
34753791decbSStephen Hemminger 		return;
34761da177e4SLinus Torvalds 	}
34771da177e4SLinus Torvalds 
3478ef87979cSStephen Hemminger 	/* This is max DELAY, this has special meaning of
3479ef87979cSStephen Hemminger 	 * "never transmit"
3480ef87979cSStephen Hemminger 	 */
3481ef87979cSStephen Hemminger 	if (unlikely(pkt_dev->delay == ULLONG_MAX)) {
3482ef87979cSStephen Hemminger 		pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX);
3483ef87979cSStephen Hemminger 		return;
3484ef87979cSStephen Hemminger 	}
3485ef87979cSStephen Hemminger 
3486ef87979cSStephen Hemminger 	/* If no skb or clone count exhausted then get new one */
34877d7bb1cfSStephen Hemminger 	if (!pkt_dev->skb || (pkt_dev->last_ok &&
34887d7bb1cfSStephen Hemminger 			      ++pkt_dev->clone_count >= pkt_dev->clone_skb)) {
34891da177e4SLinus Torvalds 		/* build a new pkt */
34901da177e4SLinus Torvalds 		kfree_skb(pkt_dev->skb);
34911da177e4SLinus Torvalds 
34921da177e4SLinus Torvalds 		pkt_dev->skb = fill_packet(odev, pkt_dev);
34931da177e4SLinus Torvalds 		if (pkt_dev->skb == NULL) {
3494f9467eaeSJoe Perches 			pr_err("ERROR: couldn't allocate skb in fill_packet\n");
34951da177e4SLinus Torvalds 			schedule();
34961da177e4SLinus Torvalds 			pkt_dev->clone_count--;	/* back out increment, OOM */
34973791decbSStephen Hemminger 			return;
34981da177e4SLinus Torvalds 		}
3499baac8564SEric Dumazet 		pkt_dev->last_pkt_size = pkt_dev->skb->len;
35001da177e4SLinus Torvalds 		pkt_dev->allocated_skbs++;
35011da177e4SLinus Torvalds 		pkt_dev->clone_count = 0;	/* reset counter */
35021da177e4SLinus Torvalds 	}
35031da177e4SLinus Torvalds 
3504ef87979cSStephen Hemminger 	if (pkt_dev->delay && pkt_dev->last_ok)
3505ef87979cSStephen Hemminger 		spin(pkt_dev, pkt_dev->next_tx);
3506ef87979cSStephen Hemminger 
3507fd2ea0a7SDavid S. Miller 	queue_map = skb_get_queue_mapping(pkt_dev->skb);
3508fd2ea0a7SDavid S. Miller 	txq = netdev_get_tx_queue(odev, queue_map);
3509fd2ea0a7SDavid S. Miller 
3510fd2ea0a7SDavid S. Miller 	__netif_tx_lock_bh(txq);
35115b8db2f5SStephen Hemminger 
35120835acfeSEric Dumazet 	if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) {
3513ef87979cSStephen Hemminger 		ret = NETDEV_TX_BUSY;
35140835acfeSEric Dumazet 		pkt_dev->last_ok = 0;
35150835acfeSEric Dumazet 		goto unlock;
35160835acfeSEric Dumazet 	}
35170835acfeSEric Dumazet 	atomic_inc(&(pkt_dev->skb->users));
351800829823SStephen Hemminger 	ret = (*xmit)(pkt_dev->skb, odev);
3519ef87979cSStephen Hemminger 
35205b8db2f5SStephen Hemminger 	switch (ret) {
35215b8db2f5SStephen Hemminger 	case NETDEV_TX_OK:
352208baf561SEric Dumazet 		txq_trans_update(txq);
35231da177e4SLinus Torvalds 		pkt_dev->last_ok = 1;
35241da177e4SLinus Torvalds 		pkt_dev->sofar++;
35251da177e4SLinus Torvalds 		pkt_dev->seq_num++;
3526baac8564SEric Dumazet 		pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
35275b8db2f5SStephen Hemminger 		break;
3528f466dba1SJohn Fastabend 	case NET_XMIT_DROP:
3529f466dba1SJohn Fastabend 	case NET_XMIT_CN:
3530f466dba1SJohn Fastabend 	case NET_XMIT_POLICED:
3531f466dba1SJohn Fastabend 		/* skb has been consumed */
3532f466dba1SJohn Fastabend 		pkt_dev->errors++;
3533f466dba1SJohn Fastabend 		break;
35345b8db2f5SStephen Hemminger 	default: /* Drivers are not supposed to return other values! */
35355b8db2f5SStephen Hemminger 		if (net_ratelimit())
35365b8db2f5SStephen Hemminger 			pr_info("pktgen: %s xmit error: %d\n",
3537593f63b0SEric Dumazet 				pkt_dev->odevname, ret);
35381da177e4SLinus Torvalds 		pkt_dev->errors++;
35395b8db2f5SStephen Hemminger 		/* fallthru */
3540ef87979cSStephen Hemminger 	case NETDEV_TX_LOCKED:
35415b8db2f5SStephen Hemminger 	case NETDEV_TX_BUSY:
35425b8db2f5SStephen Hemminger 		/* Retry it next time */
35435b8db2f5SStephen Hemminger 		atomic_dec(&(pkt_dev->skb->users));
35441da177e4SLinus Torvalds 		pkt_dev->last_ok = 0;
35451da177e4SLinus Torvalds 	}
35460835acfeSEric Dumazet unlock:
3547fd2ea0a7SDavid S. Miller 	__netif_tx_unlock_bh(txq);
35481da177e4SLinus Torvalds 
35491da177e4SLinus Torvalds 	/* If pkt_dev->count is zero, then run forever */
35501da177e4SLinus Torvalds 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
3551ef87979cSStephen Hemminger 		pktgen_wait_for_skb(pkt_dev);
35521da177e4SLinus Torvalds 
35531da177e4SLinus Torvalds 		/* Done with this */
35541da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
35551da177e4SLinus Torvalds 	}
35561da177e4SLinus Torvalds }
35571da177e4SLinus Torvalds 
35581da177e4SLinus Torvalds /*
35591da177e4SLinus Torvalds  * Main loop of the thread goes here
35601da177e4SLinus Torvalds  */
35611da177e4SLinus Torvalds 
3562ee74baa7SDavid S. Miller static int pktgen_thread_worker(void *arg)
35631da177e4SLinus Torvalds {
35641da177e4SLinus Torvalds 	DEFINE_WAIT(wait);
3565ee74baa7SDavid S. Miller 	struct pktgen_thread *t = arg;
35661da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev = NULL;
35671da177e4SLinus Torvalds 	int cpu = t->cpu;
35681da177e4SLinus Torvalds 
3569ee74baa7SDavid S. Miller 	BUG_ON(smp_processor_id() != cpu);
35701da177e4SLinus Torvalds 
35711da177e4SLinus Torvalds 	init_waitqueue_head(&t->queue);
3572d3ede327SDenis V. Lunev 	complete(&t->start_done);
35731da177e4SLinus Torvalds 
3574f9467eaeSJoe Perches 	pr_debug("starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
35751da177e4SLinus Torvalds 
3576ee74baa7SDavid S. Miller 	set_current_state(TASK_INTERRUPTIBLE);
35771da177e4SLinus Torvalds 
357883144186SRafael J. Wysocki 	set_freezable();
357983144186SRafael J. Wysocki 
3580ee74baa7SDavid S. Miller 	while (!kthread_should_stop()) {
3581ee74baa7SDavid S. Miller 		pkt_dev = next_to_run(t);
3582ee74baa7SDavid S. Miller 
3583ef87979cSStephen Hemminger 		if (unlikely(!pkt_dev && t->control == 0)) {
3584ef87979cSStephen Hemminger 			wait_event_interruptible_timeout(t->queue,
3585ef87979cSStephen Hemminger 							 t->control != 0,
3586ef87979cSStephen Hemminger 							 HZ/10);
35871b3f720bSRafael J. Wysocki 			try_to_freeze();
3588ef87979cSStephen Hemminger 			continue;
3589ee74baa7SDavid S. Miller 		}
35901da177e4SLinus Torvalds 
35911da177e4SLinus Torvalds 		__set_current_state(TASK_RUNNING);
35921da177e4SLinus Torvalds 
3593ef87979cSStephen Hemminger 		if (likely(pkt_dev)) {
35941da177e4SLinus Torvalds 			pktgen_xmit(pkt_dev);
35951da177e4SLinus Torvalds 
3596ef87979cSStephen Hemminger 			if (need_resched())
3597ef87979cSStephen Hemminger 				pktgen_resched(pkt_dev);
3598ef87979cSStephen Hemminger 			else
3599ef87979cSStephen Hemminger 				cpu_relax();
3600ef87979cSStephen Hemminger 		}
3601ef87979cSStephen Hemminger 
36021da177e4SLinus Torvalds 		if (t->control & T_STOP) {
36031da177e4SLinus Torvalds 			pktgen_stop(t);
36041da177e4SLinus Torvalds 			t->control &= ~(T_STOP);
36051da177e4SLinus Torvalds 		}
36061da177e4SLinus Torvalds 
36071da177e4SLinus Torvalds 		if (t->control & T_RUN) {
36081da177e4SLinus Torvalds 			pktgen_run(t);
36091da177e4SLinus Torvalds 			t->control &= ~(T_RUN);
36101da177e4SLinus Torvalds 		}
36111da177e4SLinus Torvalds 
361295ed63f7SArthur Kepner 		if (t->control & T_REMDEVALL) {
36131da177e4SLinus Torvalds 			pktgen_rem_all_ifs(t);
361495ed63f7SArthur Kepner 			t->control &= ~(T_REMDEVALL);
361595ed63f7SArthur Kepner 		}
361695ed63f7SArthur Kepner 
361795ed63f7SArthur Kepner 		if (t->control & T_REMDEV) {
361895ed63f7SArthur Kepner 			pktgen_rem_one_if(t);
36191da177e4SLinus Torvalds 			t->control &= ~(T_REMDEV);
36201da177e4SLinus Torvalds 		}
36211da177e4SLinus Torvalds 
362209fe3ef4SAndrew Morton 		try_to_freeze();
362309fe3ef4SAndrew Morton 
3624ee74baa7SDavid S. Miller 		set_current_state(TASK_INTERRUPTIBLE);
36251da177e4SLinus Torvalds 	}
36261da177e4SLinus Torvalds 
3627f9467eaeSJoe Perches 	pr_debug("%s stopping all device\n", t->tsk->comm);
36281da177e4SLinus Torvalds 	pktgen_stop(t);
36291da177e4SLinus Torvalds 
3630f9467eaeSJoe Perches 	pr_debug("%s removing all device\n", t->tsk->comm);
36311da177e4SLinus Torvalds 	pktgen_rem_all_ifs(t);
36321da177e4SLinus Torvalds 
3633f9467eaeSJoe Perches 	pr_debug("%s removing thread\n", t->tsk->comm);
36341da177e4SLinus Torvalds 	pktgen_rem_thread(t);
3635cdcdbe0bSLuiz Capitulino 
3636ee74baa7SDavid S. Miller 	return 0;
36371da177e4SLinus Torvalds }
36381da177e4SLinus Torvalds 
3639222f1806SLuiz Capitulino static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
36403e984840SEric Dumazet 					  const char *ifname, bool exact)
36411da177e4SLinus Torvalds {
3642c26a8016SLuiz Capitulino 	struct pktgen_dev *p, *pkt_dev = NULL;
36433e984840SEric Dumazet 	size_t len = strlen(ifname);
36441da177e4SLinus Torvalds 
36453e984840SEric Dumazet 	if_lock(t);
3646c26a8016SLuiz Capitulino 	list_for_each_entry(p, &t->if_list, list)
36473e984840SEric Dumazet 		if (strncmp(p->odevname, ifname, len) == 0) {
36483e984840SEric Dumazet 			if (p->odevname[len]) {
36493e984840SEric Dumazet 				if (exact || p->odevname[len] != '@')
36503e984840SEric Dumazet 					continue;
36513e984840SEric Dumazet 			}
3652c26a8016SLuiz Capitulino 			pkt_dev = p;
36531da177e4SLinus Torvalds 			break;
36541da177e4SLinus Torvalds 		}
36551da177e4SLinus Torvalds 
36561da177e4SLinus Torvalds 	if_unlock(t);
3657f9467eaeSJoe Perches 	pr_debug("find_dev(%s) returning %p\n", ifname, pkt_dev);
36581da177e4SLinus Torvalds 	return pkt_dev;
36591da177e4SLinus Torvalds }
36601da177e4SLinus Torvalds 
36611da177e4SLinus Torvalds /*
36621da177e4SLinus Torvalds  * Adds a dev at front of if_list.
36631da177e4SLinus Torvalds  */
36641da177e4SLinus Torvalds 
3665222f1806SLuiz Capitulino static int add_dev_to_thread(struct pktgen_thread *t,
3666222f1806SLuiz Capitulino 			     struct pktgen_dev *pkt_dev)
36671da177e4SLinus Torvalds {
36681da177e4SLinus Torvalds 	int rv = 0;
36691da177e4SLinus Torvalds 
36701da177e4SLinus Torvalds 	if_lock(t);
36711da177e4SLinus Torvalds 
36721da177e4SLinus Torvalds 	if (pkt_dev->pg_thread) {
3673f9467eaeSJoe Perches 		pr_err("ERROR: already assigned to a thread\n");
36741da177e4SLinus Torvalds 		rv = -EBUSY;
36751da177e4SLinus Torvalds 		goto out;
36761da177e4SLinus Torvalds 	}
3677c26a8016SLuiz Capitulino 
3678c26a8016SLuiz Capitulino 	list_add(&pkt_dev->list, &t->if_list);
36791da177e4SLinus Torvalds 	pkt_dev->pg_thread = t;
36801da177e4SLinus Torvalds 	pkt_dev->running = 0;
36811da177e4SLinus Torvalds 
36821da177e4SLinus Torvalds out:
36831da177e4SLinus Torvalds 	if_unlock(t);
36841da177e4SLinus Torvalds 	return rv;
36851da177e4SLinus Torvalds }
36861da177e4SLinus Torvalds 
36871da177e4SLinus Torvalds /* Called under thread lock */
36881da177e4SLinus Torvalds 
36891da177e4SLinus Torvalds static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
36901da177e4SLinus Torvalds {
36911da177e4SLinus Torvalds 	struct pktgen_dev *pkt_dev;
369239df232fSStephen Hemminger 	int err;
36933291b9dbSEric Dumazet 	int node = cpu_to_node(t->cpu);
36941da177e4SLinus Torvalds 
36951da177e4SLinus Torvalds 	/* We don't allow a device to be on several threads */
36961da177e4SLinus Torvalds 
3697d50a6b56SStephen Hemminger 	pkt_dev = __pktgen_NN_threads(ifname, FIND);
3698d50a6b56SStephen Hemminger 	if (pkt_dev) {
3699f9467eaeSJoe Perches 		pr_err("ERROR: interface already used\n");
3700d50a6b56SStephen Hemminger 		return -EBUSY;
3701d50a6b56SStephen Hemminger 	}
37021da177e4SLinus Torvalds 
37033291b9dbSEric Dumazet 	pkt_dev = kzalloc_node(sizeof(struct pktgen_dev), GFP_KERNEL, node);
37041da177e4SLinus Torvalds 	if (!pkt_dev)
37051da177e4SLinus Torvalds 		return -ENOMEM;
37061da177e4SLinus Torvalds 
3707593f63b0SEric Dumazet 	strcpy(pkt_dev->odevname, ifname);
37083291b9dbSEric Dumazet 	pkt_dev->flows = vmalloc_node(MAX_CFLOWS * sizeof(struct flow_state),
37093291b9dbSEric Dumazet 				      node);
37101da177e4SLinus Torvalds 	if (pkt_dev->flows == NULL) {
37111da177e4SLinus Torvalds 		kfree(pkt_dev);
37121da177e4SLinus Torvalds 		return -ENOMEM;
37131da177e4SLinus Torvalds 	}
37141da177e4SLinus Torvalds 	memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state));
37151da177e4SLinus Torvalds 
371695ed63f7SArthur Kepner 	pkt_dev->removal_mark = 0;
37171da177e4SLinus Torvalds 	pkt_dev->min_pkt_size = ETH_ZLEN;
37181da177e4SLinus Torvalds 	pkt_dev->max_pkt_size = ETH_ZLEN;
37191da177e4SLinus Torvalds 	pkt_dev->nfrags = 0;
37201da177e4SLinus Torvalds 	pkt_dev->clone_skb = pg_clone_skb_d;
3721fd29cf72SStephen Hemminger 	pkt_dev->delay = pg_delay_d;
37221da177e4SLinus Torvalds 	pkt_dev->count = pg_count_d;
37231da177e4SLinus Torvalds 	pkt_dev->sofar = 0;
37241da177e4SLinus Torvalds 	pkt_dev->udp_src_min = 9;	/* sink port */
37251da177e4SLinus Torvalds 	pkt_dev->udp_src_max = 9;
37261da177e4SLinus Torvalds 	pkt_dev->udp_dst_min = 9;
37271da177e4SLinus Torvalds 	pkt_dev->udp_dst_max = 9;
37281da177e4SLinus Torvalds 
372934954ddcSFrancesco Fondelli 	pkt_dev->vlan_p = 0;
373034954ddcSFrancesco Fondelli 	pkt_dev->vlan_cfi = 0;
373134954ddcSFrancesco Fondelli 	pkt_dev->vlan_id = 0xffff;
373234954ddcSFrancesco Fondelli 	pkt_dev->svlan_p = 0;
373334954ddcSFrancesco Fondelli 	pkt_dev->svlan_cfi = 0;
373434954ddcSFrancesco Fondelli 	pkt_dev->svlan_id = 0xffff;
3735e99b99b4SRobert Olsson 	pkt_dev->node = -1;
373634954ddcSFrancesco Fondelli 
373739df232fSStephen Hemminger 	err = pktgen_setup_dev(pkt_dev, ifname);
373839df232fSStephen Hemminger 	if (err)
373939df232fSStephen Hemminger 		goto out1;
37401da177e4SLinus Torvalds 
37415efdccbcSDenis V. Lunev 	pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
37425efdccbcSDenis V. Lunev 					  &pktgen_if_fops, pkt_dev);
374339df232fSStephen Hemminger 	if (!pkt_dev->entry) {
3744f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3745d50a6b56SStephen Hemminger 		       PG_PROC_DIR, ifname);
374639df232fSStephen Hemminger 		err = -EINVAL;
374739df232fSStephen Hemminger 		goto out2;
374839df232fSStephen Hemminger 	}
3749a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3750a553e4a6SJamal Hadi Salim 	pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
3751a553e4a6SJamal Hadi Salim 	pkt_dev->ipsproto = IPPROTO_ESP;
3752a553e4a6SJamal Hadi Salim #endif
375339df232fSStephen Hemminger 
375439df232fSStephen Hemminger 	return add_dev_to_thread(t, pkt_dev);
375539df232fSStephen Hemminger out2:
375639df232fSStephen Hemminger 	dev_put(pkt_dev->odev);
375739df232fSStephen Hemminger out1:
3758a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3759a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3760a553e4a6SJamal Hadi Salim #endif
37611da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
37621da177e4SLinus Torvalds 	kfree(pkt_dev);
376339df232fSStephen Hemminger 	return err;
37641da177e4SLinus Torvalds }
37651da177e4SLinus Torvalds 
3766ee74baa7SDavid S. Miller static int __init pktgen_create_thread(int cpu)
37671da177e4SLinus Torvalds {
3768cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3769d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3770ee74baa7SDavid S. Miller 	struct task_struct *p;
37711da177e4SLinus Torvalds 
37723291b9dbSEric Dumazet 	t = kzalloc_node(sizeof(struct pktgen_thread), GFP_KERNEL,
37733291b9dbSEric Dumazet 			 cpu_to_node(cpu));
37741da177e4SLinus Torvalds 	if (!t) {
3775f9467eaeSJoe Perches 		pr_err("ERROR: out of memory, can't create new thread\n");
37761da177e4SLinus Torvalds 		return -ENOMEM;
37771da177e4SLinus Torvalds 	}
37781da177e4SLinus Torvalds 
37791da177e4SLinus Torvalds 	spin_lock_init(&t->if_lock);
37801da177e4SLinus Torvalds 	t->cpu = cpu;
37811da177e4SLinus Torvalds 
3782ee74baa7SDavid S. Miller 	INIT_LIST_HEAD(&t->if_list);
3783ee74baa7SDavid S. Miller 
3784ee74baa7SDavid S. Miller 	list_add_tail(&t->th_list, &pktgen_threads);
3785d3ede327SDenis V. Lunev 	init_completion(&t->start_done);
3786ee74baa7SDavid S. Miller 
3787ee74baa7SDavid S. Miller 	p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
3788ee74baa7SDavid S. Miller 	if (IS_ERR(p)) {
3789f9467eaeSJoe Perches 		pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
3790ee74baa7SDavid S. Miller 		list_del(&t->th_list);
3791ee74baa7SDavid S. Miller 		kfree(t);
3792ee74baa7SDavid S. Miller 		return PTR_ERR(p);
3793ee74baa7SDavid S. Miller 	}
3794ee74baa7SDavid S. Miller 	kthread_bind(p, cpu);
3795ee74baa7SDavid S. Miller 	t->tsk = p;
3796ee74baa7SDavid S. Miller 
37975efdccbcSDenis V. Lunev 	pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
37985efdccbcSDenis V. Lunev 			      &pktgen_thread_fops, t);
3799d50a6b56SStephen Hemminger 	if (!pe) {
3800f9467eaeSJoe Perches 		pr_err("cannot create %s/%s procfs entry\n",
3801ee74baa7SDavid S. Miller 		       PG_PROC_DIR, t->tsk->comm);
3802ee74baa7SDavid S. Miller 		kthread_stop(p);
3803ee74baa7SDavid S. Miller 		list_del(&t->th_list);
38041da177e4SLinus Torvalds 		kfree(t);
38051da177e4SLinus Torvalds 		return -EINVAL;
38061da177e4SLinus Torvalds 	}
3807d50a6b56SStephen Hemminger 
3808ee74baa7SDavid S. Miller 	wake_up_process(p);
3809d3ede327SDenis V. Lunev 	wait_for_completion(&t->start_done);
38101da177e4SLinus Torvalds 
38111da177e4SLinus Torvalds 	return 0;
38121da177e4SLinus Torvalds }
38131da177e4SLinus Torvalds 
38141da177e4SLinus Torvalds /*
38151da177e4SLinus Torvalds  * Removes a device from the thread if_list.
38161da177e4SLinus Torvalds  */
3817222f1806SLuiz Capitulino static void _rem_dev_from_if_list(struct pktgen_thread *t,
3818222f1806SLuiz Capitulino 				  struct pktgen_dev *pkt_dev)
38191da177e4SLinus Torvalds {
3820c26a8016SLuiz Capitulino 	struct list_head *q, *n;
3821c26a8016SLuiz Capitulino 	struct pktgen_dev *p;
38221da177e4SLinus Torvalds 
3823c26a8016SLuiz Capitulino 	list_for_each_safe(q, n, &t->if_list) {
3824c26a8016SLuiz Capitulino 		p = list_entry(q, struct pktgen_dev, list);
3825c26a8016SLuiz Capitulino 		if (p == pkt_dev)
3826c26a8016SLuiz Capitulino 			list_del(&p->list);
38271da177e4SLinus Torvalds 	}
38281da177e4SLinus Torvalds }
38291da177e4SLinus Torvalds 
3830222f1806SLuiz Capitulino static int pktgen_remove_device(struct pktgen_thread *t,
3831222f1806SLuiz Capitulino 				struct pktgen_dev *pkt_dev)
38321da177e4SLinus Torvalds {
38331da177e4SLinus Torvalds 
3834f9467eaeSJoe Perches 	pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
38351da177e4SLinus Torvalds 
38361da177e4SLinus Torvalds 	if (pkt_dev->running) {
3837f9467eaeSJoe Perches 		pr_warning("WARNING: trying to remove a running interface, stopping it now\n");
38381da177e4SLinus Torvalds 		pktgen_stop_device(pkt_dev);
38391da177e4SLinus Torvalds 	}
38401da177e4SLinus Torvalds 
38411da177e4SLinus Torvalds 	/* Dis-associate from the interface */
38421da177e4SLinus Torvalds 
38431da177e4SLinus Torvalds 	if (pkt_dev->odev) {
38441da177e4SLinus Torvalds 		dev_put(pkt_dev->odev);
38451da177e4SLinus Torvalds 		pkt_dev->odev = NULL;
38461da177e4SLinus Torvalds 	}
38471da177e4SLinus Torvalds 
38481da177e4SLinus Torvalds 	/* And update the thread if_list */
38491da177e4SLinus Torvalds 
38501da177e4SLinus Torvalds 	_rem_dev_from_if_list(t, pkt_dev);
38511da177e4SLinus Torvalds 
385239df232fSStephen Hemminger 	if (pkt_dev->entry)
385339df232fSStephen Hemminger 		remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
38541da177e4SLinus Torvalds 
3855a553e4a6SJamal Hadi Salim #ifdef CONFIG_XFRM
3856a553e4a6SJamal Hadi Salim 	free_SAs(pkt_dev);
3857a553e4a6SJamal Hadi Salim #endif
38581da177e4SLinus Torvalds 	vfree(pkt_dev->flows);
38591da177e4SLinus Torvalds 	kfree(pkt_dev);
38601da177e4SLinus Torvalds 	return 0;
38611da177e4SLinus Torvalds }
38621da177e4SLinus Torvalds 
38631da177e4SLinus Torvalds static int __init pg_init(void)
38641da177e4SLinus Torvalds {
38651da177e4SLinus Torvalds 	int cpu;
3866d50a6b56SStephen Hemminger 	struct proc_dir_entry *pe;
3867d50a6b56SStephen Hemminger 
3868f9467eaeSJoe Perches 	pr_info("%s", version);
38691da177e4SLinus Torvalds 
3870457c4cbcSEric W. Biederman 	pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
3871d50a6b56SStephen Hemminger 	if (!pg_proc_dir)
3872d50a6b56SStephen Hemminger 		return -ENODEV;
38731da177e4SLinus Torvalds 
387425296d59SWang Chen 	pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
3875d50a6b56SStephen Hemminger 	if (pe == NULL) {
3876f9467eaeSJoe Perches 		pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL);
3877457c4cbcSEric W. Biederman 		proc_net_remove(&init_net, PG_PROC_DIR);
38781da177e4SLinus Torvalds 		return -EINVAL;
38791da177e4SLinus Torvalds 	}
38801da177e4SLinus Torvalds 
38811da177e4SLinus Torvalds 	/* Register us to receive netdevice events */
38821da177e4SLinus Torvalds 	register_netdevice_notifier(&pktgen_notifier_block);
38831da177e4SLinus Torvalds 
3884670c02c2SJohn Hawkes 	for_each_online_cpu(cpu) {
38858024bb24SLuiz Capitulino 		int err;
38861da177e4SLinus Torvalds 
3887ee74baa7SDavid S. Miller 		err = pktgen_create_thread(cpu);
38888024bb24SLuiz Capitulino 		if (err)
3889f9467eaeSJoe Perches 			pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n",
3890f9467eaeSJoe Perches 				   cpu, err);
38911da177e4SLinus Torvalds 	}
38928024bb24SLuiz Capitulino 
38938024bb24SLuiz Capitulino 	if (list_empty(&pktgen_threads)) {
3894f9467eaeSJoe Perches 		pr_err("ERROR: Initialization failed for all threads\n");
38958024bb24SLuiz Capitulino 		unregister_netdevice_notifier(&pktgen_notifier_block);
38968024bb24SLuiz Capitulino 		remove_proc_entry(PGCTRL, pg_proc_dir);
3897457c4cbcSEric W. Biederman 		proc_net_remove(&init_net, PG_PROC_DIR);
38988024bb24SLuiz Capitulino 		return -ENODEV;
38998024bb24SLuiz Capitulino 	}
39008024bb24SLuiz Capitulino 
39011da177e4SLinus Torvalds 	return 0;
39021da177e4SLinus Torvalds }
39031da177e4SLinus Torvalds 
39041da177e4SLinus Torvalds static void __exit pg_cleanup(void)
39051da177e4SLinus Torvalds {
3906cdcdbe0bSLuiz Capitulino 	struct pktgen_thread *t;
3907cdcdbe0bSLuiz Capitulino 	struct list_head *q, *n;
39081da177e4SLinus Torvalds 
39091da177e4SLinus Torvalds 	/* Stop all interfaces & threads */
39101da177e4SLinus Torvalds 
3911cdcdbe0bSLuiz Capitulino 	list_for_each_safe(q, n, &pktgen_threads) {
3912cdcdbe0bSLuiz Capitulino 		t = list_entry(q, struct pktgen_thread, th_list);
3913ee74baa7SDavid S. Miller 		kthread_stop(t->tsk);
3914ee74baa7SDavid S. Miller 		kfree(t);
39151da177e4SLinus Torvalds 	}
39161da177e4SLinus Torvalds 
39171da177e4SLinus Torvalds 	/* Un-register us from receiving netdevice events */
39181da177e4SLinus Torvalds 	unregister_netdevice_notifier(&pktgen_notifier_block);
39191da177e4SLinus Torvalds 
39201da177e4SLinus Torvalds 	/* Clean up proc file system */
3921d50a6b56SStephen Hemminger 	remove_proc_entry(PGCTRL, pg_proc_dir);
3922457c4cbcSEric W. Biederman 	proc_net_remove(&init_net, PG_PROC_DIR);
39231da177e4SLinus Torvalds }
39241da177e4SLinus Torvalds 
39251da177e4SLinus Torvalds module_init(pg_init);
39261da177e4SLinus Torvalds module_exit(pg_cleanup);
39271da177e4SLinus Torvalds 
3928c3d2f52dSStephen Hemminger MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se>");
39291da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Generator tool");
39301da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3931c3d2f52dSStephen Hemminger MODULE_VERSION(VERSION);
39321da177e4SLinus Torvalds module_param(pg_count_d, int, 0);
3933c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_count_d, "Default number of packets to inject");
39341da177e4SLinus Torvalds module_param(pg_delay_d, int, 0);
3935c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_delay_d, "Default delay between packets (nanoseconds)");
39361da177e4SLinus Torvalds module_param(pg_clone_skb_d, int, 0);
3937c3d2f52dSStephen Hemminger MODULE_PARM_DESC(pg_clone_skb_d, "Default number of copies of the same packet");
39381da177e4SLinus Torvalds module_param(debug, int, 0);
3939c3d2f52dSStephen Hemminger MODULE_PARM_DESC(debug, "Enable debugging of pktgen module");
3940